Buna tepki ver. SetState bir işlev değil


288

React'te yeniyim ve bir API ile çalışan bir uygulama yazmaya çalışıyorum. Bu hatayı almaya devam ediyorum:

TypeError: this.setState bir işlev değil

API yanıtını işlemeye çalıştığımda. Bu bağlamayla ilgili yanlış bir şey olduğundan şüpheleniyorum, ancak nasıl düzeltileceğini anlayamıyorum. İşte benim bileşen kodu:

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>
        );
    }
});

Yanıtlar:


348

Geri arama farklı bir bağlamda yapılır. Sen gerek bindiçin thiscallback'inde içine erişime sahip olmak için:

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));

DÜZENLEME: sizin gibi görünüyor bağlama hem zorunda initve apiçağrılar:

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, hayır. Öğreticide bağlamadan bahsedilmiyor.
Tor Haugen

8
Muhtemelen 2.5 yıl önceydi. 😁
Travis Reeder

1
Sorunu çözmek için ok işlevini kullandım. Yardım için teşekkürler
Tarun Nagpal

Birisi "geri arama farklı bir bağlamda yapılır" ile kastedilen hakkında daha fazla ayrıntı verebilir mi?
SB

135

ES6 ok işleviyle .bind (this) gereksinimini önleyebilirsiniz.

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
Bu iyi çalışıyor. Aslında, işlevin anahtar sözcüğü es6 dosyasında gösterilmemelidir.
JChen___

6
Cevabınız bana yardımcı oldu :-) Bir ES6 sınıfı ve RN 0.34 kullanarak, bir geri arama işlevi "bu" bağlamak için iki yol buldum. 1) onChange={(checked) => this.toggleCheckbox()}, 2) onChange={this.toggleCheckbox.bind(this)}.
devdanke

Eski tarayıcıları desteklemeniz gerekmediği sürece bu iyidir.
Kullanıcı

Mükemmel çözüm
Hitesh Sahu

2
GMsoF, bu iki çözüm çalışır çünkü a) bunu yaptığınızda .bind(this), çağrıldığı thisyerde ana içeriğin değerini ayarlar this.toggleCheckbox(), aksi takdirde thisgerçekte nerede yürütüldüğüne işaret eder. b) Yağ oku çözümü, değerini koruduğu için çalışır this, bu nedenle değerini şiddetle değiştirmeyerek size yardımcı olur this. JavaScript'te, thisyalnızca geçerli kapsamı ifade eder, bu nedenle bir işlev yazarsanız this, bu işlevdir. Eğer içine bir fonksiyon koyarsanız, thiso çocuk fonksiyonunun içindedir. Şişman oklar nereden çağrılır bağlamını tutmak
agm1984

37

yöntemi thisçağırmadan önce bir referans da kaydedebilirsiniz api:

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

React classbunu kendinden ziyade kullanmak için gereken tüm yöntemlerde bağlamanızı önerir function.

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

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

Veya arrow functionbunun yerine kullanabilirsiniz .


14

Sadece etkinliğinizi bağlamalısınız

eski için

// 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

Şimdi ES6 ok işlevine sahipse gerçekten bind (this) ifadesi ile karıştırırsanız ok işlevini deneyebilirsiniz

Ben böyle yaparım.

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

Ok işlevini kullanıyorsanız bunu yerel bir değişkene atamanıza gerek yoktur. Ok işlevleri ciltlemeyi otomatik olarak alır ve kapsamla ilgili sorunlardan uzak durabilirsiniz.

Aşağıdaki kod ok işlevinin farklı senaryolarda nasıl kullanılacağını açıklar

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

Şimdi es6 / 7 ile tepki olarak işlevi şu şekilde ok işlevi ile mevcut bağlama bağlayabilir, istekte bulunabilir ve şu vaatleri çözebilirsiniz:

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

Bu yöntemle, componentDidMount'ta bu işlevi kolayca çağırabilir ve html'nizi oluşturma işlevinizde oluşturmadan önce verileri bekleyebilirsiniz.

Projenizin boyutunu bilmiyorum ama kişisel olarak verileri işlemek için bileşenin mevcut durumunu kullanmamanızı tavsiye ediyorum. Redux veya Flux gibi harici bir durum veya bunun için başka bir şey kullanmalısınız.


5

ok işlevleri ana kapsama işaret ettiği için ok işlevlerini kullanın ve bu kullanılabilir. (bağlama tekniğinin yerine)


1
Harika bir özlü çözüm
Chun

çağrıda bir ok fonksiyonu olarak yöntemi çağırmak için kullanılan olsa da aynı sorunu sahip, ama sanırım ben böyle devlet fonksiyonu uygulamak zorundayım, ve tam olarak ne yaptım
Carmine Tambascia

3

Burada bu bağlam değişiyor. React sınıfının bağlamını korumak için ok işlevini kullanın.

        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

Bunu yapıyorsanız ve hala bir sorun yaşıyorsanız, sorunum iki değişkene aynı adı çağırmaktı.

companiesFirebase'den getirilen bir nesne olarak vardı ve sonra aramaya çalışıyordum this.setState({companies: companies})- bariz nedenlerden dolayı çalışmıyordu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.