反应this.setState不是一个函数


288

我是React的新手,正在尝试编写使用API​​的应用程序。我不断收到此错误:

TypeError:this.setState不是一个函数

当我尝试处理API响应时。我怀疑此绑定有问题,但我不知道如何解决它。这是我组件的代码:

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

Answers:


347

回调是在不同的上下文中进行的。您需要这样做bind才能this在回调内部进行访问:

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

编辑:看起来您必须同时绑定initapi调用:

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,不。在教程中没有提到绑定。
Tor Haugen

8
大概是2。5年前。😁–
特拉维斯·里德

1
我使用箭头功能解决了这个问题。感谢您的帮助
Tarun Nagpal

有人可以进一步详细说明“在不同上下文中进行回调”的含义吗?
SB

135

您可以通过ES6箭头功能避免对.bind(this)的需求。

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
这很好。实际上,不应在es6文件中显示function的关键字。
JChen___

6
您的回答对我有所帮助:-)使用ES6类和RN 0.34,我发现了将“ this”绑定到回调函数的两种方法。1) onChange={(checked) => this.toggleCheckbox()},2)onChange={this.toggleCheckbox.bind(this)}
devdanke '16

只要您不需要支持旧版浏览器,这就很好。
用户

完美的解决方案
Hitesh Sahu

2
GMsoF,这两个解决方案之所以起作用,是因为a)当您这样做时.bind(this),它将的值设置为this从中this.toggleCheckbox()调用的父上下文的值,否则this将引用它实际执行的位置。b)粗箭头解决方案之所以有效,是因为它保留了的值this,因此它不会通过猛烈更改的值来帮助您this。在JavaScript中,this仅指当前作用域,因此,如果您编写一个函数,this则该函数为。如果将函数放在其中,this则该函数位于该子函数中。

37

您还可以this在调用该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建议在需要使用this class代替self的所有方法中将此绑定function

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

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

或者您也可以使用arrow function


14

您只需要绑定事件

对于前

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

现在,ES6具有箭头功能,如果您真的将bind(this)表达式弄混了,可以尝试使用箭头功能。

我就是这样

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

如果使用箭头功能,则无需将其分配给局部变量。箭头功能会自动进行绑定,您可以避免与范围相关的问题。

以下代码说明了如何在不同情况下使用箭头功能

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

现在,在与es6 / 7交互时,您可以使用如下箭头函数将函数绑定到当前上下文,发出请求并解析承诺:

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

使用此方法,您可以轻松地在componentDidMount中调用此函数,然后等待数据,然后再在render函数中呈现html。

我不知道您的项目的大小,但我个人建议不要使用组件的当前状态来处理数据。您应该使用Redux或Flux之类的外部状态。


5

使用箭头函数,因为箭头函数指向父级作用域,因此将可用。(替代绑定技术)


1
绝佳的简洁解决方案

尽管在调用中曾经使用箭头函数来调用该方法,但仍存在相同的问题,但是我想我必须像这样实现状态函数,以及我所做的工作
Carmine Tambascia

3

这里的上下文正在改变。使用箭头功能保持React类的上下文。

        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

如果您正在执行此操作,但仍然遇到问题,那么我的问题是我正在调用两个名称相同的变量。

我有companies一个从Firebase传入的对象,然后试图调用this.setState({companies: companies})-它由于明显的原因而无法正常工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.