l0veisreal
l0veisreal

Reputation: 179

ReactJS How do i call setState nested Functions

Lets say that i have this component:

export default class Test extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      test: false
    };
  }

  func1 = () => {
    function update() {
      this.setState({ test: true }); // not working
    }
  };

  render() {
    return <div />;
  }
}

As you see i have func1 which is in arrow form,and there is another function update in function update() form

So how do i call setState from inside function update as seen in example ?

EDIT: the reason why i am trying to do something like this is i am using a game engine inside react component called phaser.So actually if i make update function as an arrow function for some reason phaser cant understand it and throws undefined error.update function is called 60 times in second

export default class Test extends React.Component {
      constructor(props) {
        super(props);

        this.state = {
          test: false
        };
      }
componentDidMount(){
this.func1()
}

      func1 = () => {
     var  game = new Phaser.Game(canvas_width,canvas_height,Phaser.AUTO,'gameDiv',{ preload: preload, create: create, update: update });

        function update() {
          this.setState({ test: true }); // not working
        }
      };

      render() {
        return <div />;
      }
    }

SECOND EDIT: THANKS GUYS WRITING update = update.bind(this) before var game solved it

Upvotes: 1

Views: 4190

Answers (2)

devserkan
devserkan

Reputation: 17638

You can use an arrow function again:

class Test extends React.Component {
    
  constructor(props) {
    super(props);

    this.state = {
      test: false

    };
  }

  func1 = () => {

    const update = () => {
      this.setState({ test: true }) // not working
    }
    return update;
  }

  componentDidMount() {
    this.func1()();
  }

  render() {
    console.log( this.state);
    return (
      <div></div>
    )

  }
}

ReactDOM.render(<Test />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

When you use a regular function you lose the scope of this. When you use an arrow function you can use it without worrying about this as you do in your first function. But, instead of an arrow function that would work:

func1 = () => {
    const that = this;
    return function update() {
      that.setState({ test: true }); // not working
    }
}

Or even with bind as @Tholle suggested in his comment:

func1 = () => {
    return ( function update() {
      this.setState({ test: true }); // not working
    }).bind(this);
}

Furthermore, you can define them separately and call the update function inside the func1.

func1 = () => {
    this.update();
};

update() {
  this.setState({ test: true }); // not working
}

This works too, because you are auto-binding your func1 function to this and your update function is invoked from there, keepin this scope.

Upvotes: 2

Nick Brady
Nick Brady

Reputation: 6592

you can pass this in as an argument, perhaps calling it self within the function. I.e self.setState. You could also bind or call the function passing the this as an argument. The important thing is that this still references the correct React component.

also, I'm a little confused why you're defining a function which returns a function like that. Could you just pass the function in point free form instead and not need to worry about this issue? You still need to bind the function to this..

export default class Test extends React.Component {
  constructor(props) {
    super(props);
    this.func1 = this.func1.bind(this)
    this.state = {
      test: false
    };
  }

  func1() {
    this.setState({ test: true });
  };

  render() {
    return <div callback={this.func1} />;
  }
}

Upvotes: 1

Related Questions