简体   繁体   中英

this.setState is undefined

I keep seeing answers that say to use => or .bind(this) but neither of those solutions worked.

import React, { Component } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';

export default class MyWeatherApp extends Component {
  constructor(props) {
  super(props);

  this.state = {};
}

getInitialState() {
  return {
    zip: '',
    forecast: null,
  };
}

_handleTextChange(event) {
  var zip = event.nativeEvent.text;
  this.setState({zip: zip});
}

Solution:

_handleTextChange = (event) => {
  var zip = event.nativeEvent.text;
  this.setState({zip: zip});
  alert('click');
}

When you extend React.Component with ES2015 class syntax you need to bind your action handlers to a context of your class.

Try this: onChange={e => _handleTextChange(e)}

Generally, it's better not to use arrow functions or bind methods inside render as it generates a new copy of the function on any render call. Move function declaration to the class constructor .

I personally prefer to use arrow functions as class properties in this case

class MyClass extends React.Component {

  handleClick = () => {
    // your logic
  };

  render() {
    return (
      <button onClick={this.handleClick}>Click me</button>
    );
  }
}

It's not a part of ES2015 specification but babel stage-0 preset supports this syntax

You can read more about context binding in React in this article

Let me write this in detail. As I had to waste a lot of time in researching it & I don't want anyone to repeat this...

If you dont use Arrow Function you have to bind this like Line '9'

class MyClass extends React.Component {

  handleButtonClick(){
    console.log("Hello from here");
  };

  render() {
    return (
      <button onClick={this.handleButtonClick.bind(this)}>Click me</button>
    );
  }
}

Another way is using ES6 Arrow function. You need not bind 'this' in this case. Installing 'babel stage-1 preset' will support this.

Run the command below in your project:

npm i babel-preset-stage-1 --save

Your .babelrc will look like this. Specially 'stage-1' in the preset.

{
  "presets": ["es2015", "react", "stage-1"],
  "env": {
    "development": {
      "plugins": ["react-hot-loader/babel"]
    }
  }
}

Your component will be like this, as I said:

class MyClass extends React.Component {

      handleButtonClick = () => {
        console.log("Hello from here");
      };

      render() {
        return (
          <button onClick={this.handleButtonClick}>Click me</button>
        );
      }
    }

The problem was: I had that ERROR : this.setState is not a function

Given i was binding my function to the state in component constructor, like this:

 this.getRequestData = this.getRequestData.bind(this);

and my function was:

getRequestData(){
    axios.post('http://example.com/getInfo', jsonData)
                        .then(function (res) {
                            console.log(res);
                        })
                        .catch(function (error) {
                            console.log(error);
                        });
                        this.setState({ stateVaribale });
                    })
}

the solution is to use arrow functions instead of using keyword function in the axios request, cause it's confusing to react to refer to the function in axios request instead of the component state .

getRequestData(){
axios.post('http://example.com/getInfo', jsonData)
                        .then(res => {
                        console.log(res);
                        })
                        .catch(error => {
                            console.log(error);
                        });
                        this.setState({ stateVaribale });
                    })}

also you can bind this in constructor like this

class MyClass extends React.Component {
  constructor(props){
    super(props);
    this.handleButtonClick = this.handleButtonClick.bind(this);
 }
  handleButtonClick(){
    console.log("Hello from here");
  }

  render() {
    return (
      <button onClick={this.handleButtonClick}>Click me</button>
    );
  }
}

in react native, we got this error when we use axios, as an example

    componentDidMount(){
    axios.get('https://the request url')
    .then( function(response) {
      this.setState({products:response.data.products});
    })
    .catch(function(error) {
      console.log(error);
    })
}

if we try like this we got :

undefined is not an object (evaluating 'this.setState')

so how we can fix this, we can fix it using arrow function like this

componentDidMount(){
        axios.get('https://the request url')
        .then( (response)=> {
          this.setState({products:response.data.products});
        })
        .catch((error)=> {
          console.log(error);
        })
    }

this will solve the problem, hope this will helpful

you need to bind your action otherwise you can see error called undefined in your browser there are three methods for binding your action

  1. bind the handler in the render method this.chngHandler.bind(this)

for eg-

export class EventBind extends Component{
constructor(){
    super()
    this.state = {
        msg:'hello'
    }
}
chngHandler(){
    this.setState({
         msg:'Good bye'
    })
}
render(){
    return(
        <div>
            {this.state}
            <button onClick={this.chngHandler.bind(this)}>click</button>
        </div>
    )
 } }
  1. arrow function approach in render ()=>this.EventHandler()

for example-

export class EventBind extends Component{
constructor(){
    super()
    this.state = {
        msg:'hello'
    }
}
chngHandler(){
    this.setState({
         msg:'Good bye'
    })
}
render(){
    return(
        <div>
            {this.state}
            <button onClick={()=>this.chngHandler()}>click</button>
        </div>
    )
}}`

3.Binding the event handler in the constructor this.EventHandler = this.EventHandler.bind(this) for example-:

export class EventBind extends Component{
constructor(){
    super()
    this.state = {
        msg:'hello'
    }
    this.chngHandler = this.chngHandler.bind(this)
}
chngHandler(){
    this.setState({
         msg:'Good bye'
    })
}
render(){
    return(
        <div>
            {this.state}
            <button onClick={this.chngHandler}>click me </button>
        </div>
    )
}}

because the binding happens once in the constructor this is better than a binding in the render method

3rd approach can also be done like this -:

export class EventBind extends Component{
constructor(){
    super()
    this.state = {
        msg:'hello'
    }
    this.chngHandler = this.chngHandler.bind(this)
}
// chngHandler(){
//     this.setState({
//          msg:'Good bye'
//     })
// }
chngHandler = ()=>{
    this.setState({
        msg:'Good Bye'
    })
}
render(){
    return(
        <div>
            {this.state}
            <button onClick={this.chngHandler}>click me </button>
        </div>
    )
}}

works for react-native too when you use fat arrow functions inside the methods you are invoking another function. eg .then((response) => { this.setState({....}) }

Whenever you are using this inside an api call like axios request There are cases where your 'this' context remains to be undefined. Elaborating few of them here-:

`

import react from 'React'
class Test extends from React.Component {
constructor() {
super();
this.state = {
data: '',
error: ''
}
}
componentDidMount() {
url = 'http://abc.go.com';
axios.get(url).then(function(resposne) {   // Everything fine till now
this.setState({ data: response });   //Oops this context is undefined
}
).catch(function(err) {
 this.setState({ error: err });       // again this context remains to be undefined
});
}
render() {
return ( <div>this.state.data</div> ) 
}
}`

when you will run the above code you will definitely get a type error like setState of undefined is being called, Something similar to this.

How can you solve this? There are two methods that you can follow to solve this particular type of question-:

First one is you can define a variable inside the function where you'll be calling the api and assign it the value of 'this' and from that variable you can reference your state object.

import react from 'React'
class Test extends React.Component
{
  constructor() { 
     super();
     this.state = {
       data: '',
       error: ''
  };
  componentDidMount() {
   let url = 'http://abc.go.com';
   currentContext = this;   // variable to be assigned this context
   axios.get(url).then(function(resposne) {   // Everything fine till now
   currentContext.setState({ data: response });   //Oops this context is undefined
   }
   ).catch(function(err) {
  currentContext.setState({ error: err });       // again this context remains to be undefined
 });
  }
 render() {
  return ( <div>this.state.data</div> ) 
 }
 }

Second method that you can use is by defining arrow function in axios like given below

axios.get(url).then((response) => {
  this.setState({ data: response })     //will always be bound to the this context
}) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM