Bereaksi this.setState bukan fungsi


288

Saya baru di Bereaksi dan saya mencoba menulis aplikasi yang bekerja dengan API. Saya terus mendapatkan kesalahan ini:

TypeError: this.setState bukan fungsi

ketika saya mencoba menangani respons API. Saya curiga ada yang salah dengan pengikatan ini, tetapi saya tidak tahu cara memperbaikinya. Berikut kode komponen saya:

var AppMain = React.createClass({
    getInitialState: function() {
        return{
            FirstName: " "
        };
    },
    componentDidMount:function(){
        VK.init(function(){
            console.info("API initialisation successful");
            VK.api('users.get',{fields: 'photo_50'},function(data){
                if(data.response){
                    this.setState({ //the error happens here
                        FirstName: data.response[0].first_name
                    });
                    console.info(this.state.FirstName);
                }

            });
        }, function(){
        console.info("API initialisation failed");

        }, '5.34');
    },
    render:function(){
        return (
            <div className="appMain">
            <Header  />
            </div>
        );
    }
});

Jawaban:


348

Panggilan balik dibuat dalam konteks yang berbeda. Anda perlu binduntuk thisuntuk memiliki akses dalam callback:

VK.api('users.get',{fields: 'photo_50'},function(data){
    if(data.response){
        this.setState({ //the error happens here
            FirstName: data.response[0].first_name
        });
        console.info(this.state.FirstName);
    }

}.bind(this));

EDIT: Sepertinya Anda harus mengikat keduanya initdan apimenelepon:

VK.init(function(){
        console.info("API initialisation successful");
        VK.api('users.get',{fields: 'photo_50'},function(data){
            if(data.response){
                this.setState({ //the error happens here
                    FirstName: data.response[0].first_name
                });
                console.info(this.state.FirstName);
            }

        }.bind(this));
    }.bind(this), function(){
    console.info("API initialisation failed");

    }, '5.34');

@ TravisReeder, tidak. Tidak disebutkan tentang binding dalam tutorial.
Tor Haugen

8
Mungkin ada 2,5 tahun yang lalu. 😁
Travis Reeder

1
Saya menggunakan fungsi panah untuk menyelesaikan masalah. Terima kasih atas bantuannya
Tarun Nagpal

Bisakah seseorang menjelaskan lebih jauh apa yang dimaksud dengan "panggilan balik dibuat dalam konteks yang berbeda"?
SB

135

Anda dapat menghindari kebutuhan .bind (this) dengan fungsi panah ES6.

VK.api('users.get',{fields: 'photo_50'},(data) => {
        if(data.response){
            this.setState({ //the error happens here
                FirstName: data.response[0].first_name
            });
            console.info(this.state.FirstName);
        }

    });

1
Ini bekerja dengan baik. Bahkan, kata kunci fungsi tidak boleh ditampilkan dalam file es6.
JChen___

6
Jawaban Anda membantu saya :-) Menggunakan kelas ES6 dan RN 0,34, saya menemukan dua cara untuk mengikat "ini" ke fungsi panggilan balik. 1) onChange={(checked) => this.toggleCheckbox()}, 2) onChange={this.toggleCheckbox.bind(this)}.
devdanke

Ini bagus asalkan Anda tidak perlu mendukung browser lama.
Pengguna

Solusi sempurna
Hitesh Sahu

2
GMsoF, kedua solusi itu bekerja karena a) ketika Anda melakukannya .bind(this), itu menetapkan nilai thisuntuk konteks induk dari mana this.toggleCheckbox()dipanggil, jika tidak thisakan merujuk ke tempat itu sebenarnya dieksekusi. b) Solusi panah gemuk berfungsi karena mempertahankan nilai this, sehingga membantu Anda dengan tidak mengubah nilai this. Dalam JavaScript, thiscukup merujuk ke ruang lingkup saat ini, jadi jika Anda menulis fungsi, thisapakah fungsi itu. Jika Anda meletakkan fungsi di dalamnya, thisada di dalam fungsi anak itu. Anak panah gemuk menjaga konteks tempat dipanggilnya
agm1984

37

Anda juga dapat menyimpan referensi thissebelum memohon apimetode:

componentDidMount:function(){

    var that = this;

    VK.init(function(){
        console.info("API initialisation successful");
        VK.api('users.get',{fields: 'photo_50'},function(data){
            if(data.response){
                that.setState({ //the error happens here
                    FirstName: data.response[0].first_name
                });
                console.info(that.state.FirstName);
            }
        });
    }, function(){
        console.info("API initialisation failed");

    }, '5.34');
},

32

Bereaksi merekomendasikan untuk mengikat ini dalam semua metode yang perlu menggunakan ini, classbukan ini dari diri function.

constructor(props) {
    super(props)
    this.onClick = this.onClick.bind(this)
}

 onClick () {
     this.setState({...})
 }

Atau Anda dapat menggunakannya arrow functionsebagai gantinya.


14

Anda hanya perlu mengikat acara Anda

untuk mantan

// place this code to your constructor

this._handleDelete = this._handleDelete.bind(this);

// and your setState function will work perfectly

_handleDelete(id){

    this.state.list.splice(id, 1);

    this.setState({ list: this.state.list });

    // this.setState({list: list});

}

10

Sekarang ES6 memiliki fungsi panah, sangat membantu jika Anda benar-benar bingung dengan ekspresi bind (ini) Anda dapat mencoba fungsi panah

Inilah yang saya lakukan.

componentWillMount() {
        ListApi.getList()
            .then(JsonList => this.setState({ List: JsonList }));
    }

 //Above method equalent to this...
     componentWillMount() {
         ListApi.getList()
             .then(function (JsonList) {
                 this.setState({ List: JsonList });
             }.bind(this));
 }

8

Anda tidak perlu menetapkan ini ke variabel lokal jika Anda menggunakan fungsi panah. Fungsi panah akan mengikat secara otomatis dan Anda dapat menghindari masalah terkait ruang lingkup.

Kode di bawah ini menjelaskan cara menggunakan fungsi panah di berbagai skenario

componentDidMount = () => {

    VK.init(() => {
        console.info("API initialisation successful");
        VK.api('users.get',{fields: 'photo_50'},(data) => {
            if(data.response){
                that.setState({ //this available here and you can do setState
                    FirstName: data.response[0].first_name
                });
                console.info(that.state.FirstName);
            }
        });
    }, () => {
        console.info("API initialisation failed");

    }, '5.34');
 },

5

Sekarang dalam reaksi dengan es6 / 7 Anda dapat mengikat fungsi ke konteks saat ini dengan fungsi panah seperti ini, membuat permintaan dan menyelesaikan janji seperti ini:

listMovies = async () => {
 const request = await VK.api('users.get',{fields: 'photo_50'});
 const data = await request.json()
 if (data) {
  this.setState({movies: data})
 }
}

Dengan metode ini Anda dapat dengan mudah memanggil fungsi ini di componentDidMount dan menunggu data sebelum membuat html Anda di fungsi render Anda.

Saya tidak tahu ukuran proyek Anda, tetapi saya pribadi menyarankan agar tidak menggunakan status komponen saat ini untuk memanipulasi data. Anda harus menggunakan kondisi eksternal seperti Redux atau Flux atau sesuatu yang lain untuk itu.


5

gunakan fungsi panah, karena fungsi panah menunjuk ke lingkup induk dan ini akan tersedia. (pengganti teknik mengikat)


1
Solusi ringkas yang bagus
Chun

memiliki masalah yang sama meskipun digunakan untuk memanggil metode ini sebagai fungsi panah dalam panggilan, tapi saya rasa saya harus menerapkan fungsi negara seperti itu, dan persis apa yang telah saya lakukan
Carmine Tambascia

3

Di sini konteks ini berubah. Gunakan fungsi panah untuk menjaga konteks kelas Bereaksi.

        VK.init(() => {
            console.info("API initialisation successful");
            VK.api('users.get',{fields: 'photo_50'},(data) => {
                if(data.response){
                    this.setState({ //the error happens here
                        FirstName: data.response[0].first_name
                    });
                    console.info(this.state.FirstName);
                }

            });
        }, function(){
        console.info("API initialisation failed");

        }, '5.34');

1

Jika Anda melakukan ini dan masih memiliki masalah, masalah saya adalah saya memanggil dua variabel dengan nama yang sama.

Saya memiliki companiesobjek yang dibawa dari Firebase, dan kemudian mencoba menelepon this.setState({companies: companies})- itu tidak berfungsi karena alasan yang jelas.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.