react set state callback correct way to pass an argument

后端 未结 1 1763
执念已碎
执念已碎 2021-01-19 05:29

I am using React\'s setState method, and calling another function when the state has been updated.

Is there a preferred approach as to how to call the f

相关标签:
1条回答
  • 2021-01-19 06:18

    Both of the approaches below work but is there any performance implications of using one over the other?

    There's a correctness implication: The first one is incorrect, the second one is correct. :-)

    In your first example, you're calling this.clearResult(500) and then calling setState (with the result of calling this.clearResult(500) — undefined, in your example — as its second argument). this.setState(prevState => { ... }, this.clearResult(500)); is just like foo(bar()) — first it calls bar, then it passes the result of calling it into foo.

    In your second example, you're passing a function into setState that it will call when the state is updated.

    You want the second form (or one of the various equivalents to it).

    this.setState(prevState => {
      return {
        result: '1-1',
      }
    }, () => this.clearResult(500));
    // or:  }, this.clearResult.bind(this, 500));
    // But the arrow is clear and idiomatic
    

    Here's proof that your first example is calling clearResult before calling setState, and before your state change callback is called:

    class Example extends React.Component {
      constructor(...args) {
        super(...args);
        this.state = {value: "a"};
      }
      
      // Overriding it PURELY to show what's happening
      setState(...args) {
        console.log("setState called");
        return super.setState(...args);
      }
      
      componentDidMount() {
        this.setState(
          () => {
            console.log("state change callback");
            return {value: "b"};
          },
          this.clearResult(500)
        );
      }
      
      clearResult(delay) {
        console.log("clearResult called");
        setTimeout(() => {
          this.setState({value: "c"});
        }, delay);
      }
      
      render() {
        return <div>{this.state.value}</div>;
      }
    }
    
    ReactDOM.render(
      <Example />,
      document.getElementById("root")
    );
    <div id="root"></div>
    <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>

    whereas with () => this.clearResult(500) instead, clearResult is called after setState (and after the state change):

    class Example extends React.Component {
      constructor(...args) {
        super(...args);
        this.state = {value: "a"};
      }
      
      // Overriding it PURELY to show what's happening
      setState(...args) {
        console.log("setState called");
        return super.setState(...args);
      }
      
      componentDidMount() {
        this.setState(
          () => {
            console.log("state change callback");
            return {value: "b"};
          },
          () => this.clearResult(500)
        );
      }
      
      clearResult(delay) {
        console.log("clearResult called");
        setTimeout(() => {
          this.setState({value: "c"});
        }, delay);
      }
      
      render() {
        return <div>{this.state.value}</div>;
      }
    }
    
    ReactDOM.render(
      <Example />,
      document.getElementById("root")
    );
    <div id="root"></div>
    <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>


    Side note 1: If you want, you can be a bit more concise:

    this.setState(
        () => ({ result: '1-1' }),
        () => this.clearResult(500)
    );
    

    Side note 2: There's no need to use the function form if the new state you're passing isn't based on current state or props. In your example, it isn't, so yours is one of the places where using the non-callback form is okay:

    this.setState(
        { result: '1-1' },
        () => this.clearResult(500)
    );
    

    That would not be okay if you were using something from this.state or this.props. In that situation, use the callback form and its prevState and props parameters. Always. And there's little harm in always using the callback form, the overhead of a function call is exceptionally trivial on modern JavaScript engines. (It was even trivial on the slowest JS engine of this century: The one in IE6.)

    More on that here and here.

    0 讨论(0)
提交回复
热议问题