【问题标题】:react set state callback correct way to pass an argument反应设置状态回调正确的方法来传递参数
【发布时间】:2018-02-07 15:12:33
【问题描述】:

我正在使用 React 的 setState 方法,并在状态更新后调用另一个函数。

关于如何调用作为回调传递给setState 的函数是否有首选方法。

以下两种方法都有效,但使用其中一种方法是否会对性能产生影响?

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

  this.setState(prevState => {
    return {
      result: '1-1',

    }
  }, () => this.clearResult(500))

我的clearPin 方法如下所示。所有这些代码都在一个 React 组件中。

  clearResult(time) {

    setTimeout(() => {
      this.setState({
        result: '0-0'
      })
    }, time)

  }

【问题讨论】:

  • clearResultclearPin?

标签: javascript reactjs ecmascript-6


【解决方案1】:

以下两种方法都有效,但使用其中一种方法是否会对性能产生影响?

有一个正确性的含义:第一个是不正确的,第二个是正确的。 :-)

在您的第一个示例中,您调用 this.clearResult(500) 并且 然后 调用 setState(调用 this.clearResult(500) - undefined 的结果,在您的示例中 - 作为它的第二个参数)。 this.setState(prevState => { ... }, this.clearResult(500)); 就像 foo(bar()) - 首先它调用 bar,然后将调用它的结果传递给 foo

在您的第二个示例中,您将一个函数传递给setState,当状态更新时它将调用该函数。

你想要第二种形式(或它的各种等价形式之一)。

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

这里证明您的第一个示例是在调用clearResult 之前调用setState,并且在调用您的状态更改回调之前:

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>

而用() =&gt; this.clearResult(500) 代替,clearResultsetState 之后调用(并且在状态更改之后):

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>

旁注1:如果你愿意,你可以更简洁一点:

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

旁注2:如果您传递的新状态不是基于当前状态或道具,则无需使用函数形式。在您的示例中,情况并非如此,因此您的示例是可以使用非回调表单的地方之一:

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

如果您使用来自this.statethis.props 的东西,那不会没问题。在这种情况下,使用回调表单及其prevStateprops 参数。总是。而且总是使用回调形式并没有什么坏处,函数调用的开销在现代 JavaScript 引擎上是非常微不足道的。 (在本世纪最慢的 JS 引擎上什至微不足道:IE6 中的那个。)

更多关于herehere

【讨论】:

  • 如果第一个不正确,它应该不起作用吗? :-S
  • @peterflanagan:它正在工作,因为它发生 clearResult 正在设置一个计时器并且它发生 React 在此之前正在执行状态更新计时器触发。但这仍然是不正确的。 :-) 它引入了竞争条件(当然,在大多数情况下,您根本不会设置计时器,因此您的“完成后”甚至会在状态更新开始之前运行)。
  • @peterflanagan:计算机速度很快。由于您的超时时间为 500 毫秒,因此它似乎可以正常工作。如果您删除超时,您将看到函数未按您想要的顺序调用。
  • @peterflanagan:很高兴。 :-) 我添加了两个可实时运行的示例来说明调用顺序。编码愉快!
猜你喜欢
  • 2020-07-07
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多