反应this.setState不是一个函数

时间:2015-06-25 08:59:31

标签: javascript reactjs

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

11 个答案:

答案 0 :(得分:272)

回调是在不同的上下文中进行的。您需要bindthis才能访问回调:

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

答案 1 :(得分:107)

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

    });

答案 2 :(得分: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');
},

答案 3 :(得分:9)

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

答案 4 :(得分:9)

您只需要绑定您的活动

表示前 -

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

}

答案 5 :(得分:8)

React建议将此绑定到需要使用text-align: center !important;而不是自身class的所有方法中。

function

或者您也可以改用constructor(props) { super(props) this.onClick = this.onClick.bind(this) } onClick () { this.setState({...}) }

答案 6 :(得分:5)

Now in react with es6/7 you can bind function to current context with arrow function like this, make request and resolve promises like this :

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

With this method you can easily call this function in the componentDidMount and wait the data before render your html in your render function.

I don't know the size of your project but I personally advise against using the current state of the component to manipulate datas. You should use external state like Redux or Flux or something else for that.

答案 7 :(得分:5)

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

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

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

答案 8 :(得分: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');

答案 9 :(得分:2)

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

答案 10 :(得分:0)

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

我将 @Echo Off Set "Name=%DATE%" Set "Name=%Name:~-10,2%-%Name:~-7,2%-%Name:~-4%_job" MD "C:\%Name%" 2>Nul CD /D "C:\%Name%" || Exit /B ( Echo open 192.168.31.93 Echo *user* Echo *password* Echo binary Echo cd *directory* Echo mget *.* Echo close )>"ftp.txt" FTP -i -s:ftp.txt Del "ftp.txt" 2>Nul Exit /B 作为从Firebase引入的对象,然后试图调用companies-出于明显的原因,它无法正常工作。