更合理的 setState()
原文发表在我的博客:http://www.erichain.me/2017/04/17/2017-04-17-more-reasonable-setstate/ 原谅我说了一些废话,以下是正文。 先说说大家都知道的 在 React 文档的 State and Lifecycle 一章中,其实有明确的说明 setState() 的用法,向 setState() 中传入一个对象来对已有的 state 进行更新。 比如现在有下面的这样一段代码: class MyComponent extends React.Component { this.setState({ 最基本的用法世人皆知,但是,在 React 的文档下面,还写着,处理关于异步更新 state 的问题的时候,就不能简单地传入对象来进行更新了。这个时候,需要采用另外一种方式来对 state 进行更新。 setState() 不仅能够接受一个对象作为参数,还能够接受一个函数作为参数。函数的参数即为 state 的前一个状态以及 props。 所以,我们可以向下面这样来更新 state: this.setState((prevState,props) => ({ count: prevState.count + 1 })); 区别 我们来详细探讨一下为什么会有两种设置 state 的方案,他们之间有什么区别,我们应该在何时使用何种方案来更新我们的 state 才是最好的。 此处,为了能够明确的看出 state 的更新,我们采用一个比较简单的例子来进行说明。 我们设置一个累加器,在 state 上设置一个 count 属性,同时,为其增加一个 increment 方法,通过这个 increment 方法来更新 count。 此处,我们采用给 setState() 传入对象的方式来更新 state,同时,我们在此处设置每调用一次 increment 方法的时候,就调用两次 setState()。具体的原因我们在后文中会讲解。 具体的代码如下: class IncrementByObject extends React.Component { // 此处设置调用两次 setState() this.setState({ count: this.state.count + 1 }); } render() { IncrementByObject {this.state.count} ); } } ReactDOM.render( 其实,在 React 内部,对于这种情况,采用的是对象合并的操作,就和我们所熟知的 Object.assign() 执行的结果一样。 比如,我们有以下的代码: Object.assign({},{ a: 2,b: 3 },{ a: 1,c: 4 }); 用简短的代码说明就是这样: this.setState({ // 同理于 我们将上面的累加器采用另外的方式来实现一次,在 setState() 的时候,我们采用传入一个函数的方式来更新我们的 state。 class IncrementByFunction extends React.Component { increment() { render() { IncrementByFunction {this.state.count} ); } } ReactDOM.render( 我们可以通过查看 React 的源代码来找出这两种更新 state 的区别 (此处只展示通过传入函数进行更新的方式的部分源码)。 在 React 的源代码中,我们可以看到这样一句代码: this.updater.enqueueSetState(this,partialState,callback,‘setState’); queue.push(partialState); 问题所在 那么,这就是传入对象来更新 state 会导致的问题吗?当然,这只是问题之一,还不是主要的问题。 我们之前也说过,我们在处理异步更新的时候,需要用到传入函数的方式来更新我们的 state。这样,在更新下一个 state 的时候,我们能够正确的获取到之前的 state,并在在其基础之上进行相应的修改。而不是简单地执行所谓的对象合并。 所以说,我们建议,在使用 setState 的时候,采用传入函数来更新 state 的方式,这样也是一个更合理的方式。 我在 CodePen 上将这两个效果组合到了一起,感兴趣的话,你可以去试着点击一下。 See the Pen React Functional setState by Erichain (@Erichain) on CodePen. References Functional setState is the future of React (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |