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

답변:


348

콜백은 다른 상황에서 이루어집니다. 당신은 필요 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');

@TravisReeder, 아니오. 튜토리얼에는 bind에 대한 언급이 없습니다.
Tor Haugen

8
아마 2.5 년 전에 있었을 것입니다. 😁
Travis Reeder

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
이것은 잘 작동합니다. 실제로 function 키워드는 es6 파일에 표시되지 않아야합니다.
JChen___

6
귀하의 답변이 도움이되었습니다 :-) ES6 클래스와 RN 0.34를 사용하여 "this"를 콜백 함수에 바인딩하는 두 가지 방법을 찾았습니다. 1) onChange={(checked) => this.toggleCheckbox()}, 2) onChange={this.toggleCheckbox.bind(this)}.
devdanke

오래된 브라우저를 지원할 필요가없는 한 좋습니다.
사용자

완벽한 솔루션
Hitesh Sahu

2
GMsoF는 두 가지 솔루션이 작동하기 때문에 a) 할 때 .bind(this)의 값을 호출 this하는 상위 컨텍스트로 값을 설정하고 this.toggleCheckbox()그렇지 않으면 this실제로 실행 된 위치를 참조합니다. b) 지방 화살표 솔루션은의 가치를 유지하기 때문에 효과가 있으므로의 가치를 this심하게 변경하지 않도록 도와줍니다 this. JavaScript에서는 this단순히 현재 범위를 참조하므로 함수를 작성하면 this해당 함수입니다. 그 안에 함수를 넣으면 this그 자식 함수 안에 있습니다. 지방 화살표에서 호출 곳의 환경 유지
agm1984

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는 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에는 화살표 기능이 있습니다. 바인드 (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에서이 함수를 쉽게 호출하고 렌더링 함수에서 html을 렌더링하기 전에 데이터를 기다릴 수 있습니다.

프로젝트의 크기를 모르지만 데이터를 조작하기 위해 구성 요소의 현재 상태를 사용하지 않도록 개인적으로 조언합니다. Redux 또는 Flux와 같은 외부 상태를 사용해야합니다.


5

화살표 기능은 부모 범위를 가리 키므로 화살표 기능을 사용하면 사용할 수 있습니다. (바인드 기술의 대체)


1
훌륭한 간결한 솔루션
Chun

같은 문제가 있지만 호출에서 화살표 함수로 메소드를 호출하는 데 사용되었지만 상태 함수를 구현해야하며 정확하게 수행 한 것 같습니다
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

당신이 이것을하고 여전히 문제가 있다면, 내 문제는 두 개의 변수를 같은 이름으로 부르고 있다는 것입니다.

나는 companiesFirebase에서 가져온 물건을 가지고 있었고 전화를 시도했습니다 this.setState({companies: companies}). 명백한 이유로 작동하지 않았습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.