博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【React】为什么我不再使用setState?
阅读量:5750 次
发布时间:2019-06-18

本文共 3793 字,大约阅读时间需要 12 分钟。


几个月前,我开始停止使用React的 setState 。我并不是不再需要组件状态,而且不再用React来管理我的组件状态。

setState对于新手来说不是很友好,即使是有经验的React程序员在使用setState时,也很容易出bug,比如:

Bug产生的原因是忘记了React的state是异步的;从日志打印延迟可以看出来。

React的已将把使用setState可能会出现的所有问题都总结了:

注意:

永远不要直接修改this.state,需要通过调用this.setState方法来替换你修改后的值。把this.state当做不可变数据来处理。

setState()不会马上去改变this.state,而是会排队等待处理,所以当你调用setState()后访问this.state,有可能会返回旧的state

当你调用setState()时,无法保证是同步执行的,因为为了保证性能可能会被批处理。

setState()总是会触发render()进行重新渲染,除非在shouldComponentUpdata()控制了渲染逻辑。如果用了可变数据结构以及在shouldComponentUpdata()中并没有控制渲染逻辑,调用setState()将不会触发重新渲染渲染。

总的来说,使用setState会带来三个问题:

1. setState是异步的

许多开发人员起初并没有意识到这一点,当你设置了新的state,却发现没有变化,这是setState最诡异的地方,因为setState调用的时候看起来并不是异步。比如下面的代码:

class Select extends React.Component {  constructor(props, context) {    super(props, context)    this.state = {      selection: props.values[0]    };  }  render() {    return (      
    {this.props.values.map(value =>
  • this.onSelect(value)} > {value}
  • )}
) } onSelect(value) { this.setState({ selection: value }) this.fireOnSelect() } onKeyDown = (e) => { const {values} = this.props const idx = values.indexOf(this.state.selection) if (e.keyCode === 38 && idx > 0) { /* up */ this.setState({ selection: values[idx - 1] }) } else if (e.keyCode === 40 && idx < values.length -1) { /* down */ this.setState({ selection: values[idx + 1] }) } this.fireOnSelect() } fireOnSelect() { if (typeof this.props.onSelect === "function") this.props.onSelect(this.state.selection) /* not what you expected..*/ }}ReactDOM.render(

乍一看没什么问题,但是这个select组件有一个bug,上面的git图已经很好的证明了。onSelect()方法触发时总是得到前一个state.selection的值,因为setState还没有完成,fireOnSelect就被调用了。我认为应该把setState重新命名为scheduleState或者要求传入回调。

这个bug很容易修复,棘手的地方在于你很难发现它。

2. setState引起没有必要的渲染

setState的第二个问题在于它总是会触发重新渲染,很多时候这种渲染是没有必要的。你可以通过(React提供的性能工具)来检测它会在什么时候重新渲染。从三个方面来粗略的讲为什么重新渲染有时候是没有必要的:

  • 当新的state和旧的state是一样的。可以通过shouldComponentUpdate来解决,也可以用纯渲染库来解决。

  • 只有某些时候state的改变才和渲染有关系。

  • 第三,某些时候state和视图层一点关系都没有,比如用来管理事件的监听器,定时器等相关的state

3. setState不可能管理所有组件的状态

接着上面最后那点说,不是所有的组件状态都需要通过setState来储存和更新。大多数复杂的组件通常需要管理定时器循环,接口请求,事件等等。如果用setState来管理,不仅仅会引起没有必要渲染,而且会造成死循环。

用MobX来管理组件状态

代码如下:

import {observable} from "mobx"import {observer} from "mobx-react"@observer class Select extends React.Component {  @observable selection = null; /* MobX managed instance state */  constructor(props, context) {    super(props, context)    this.selection = props.values[0]  }  render() {    return (      
    {this.props.values.map(value =>
  • this.onSelect(value)} > {value}
  • )}
) } onSelect(value) { this.selection = value this.fireOnSelect() } onKeyDown = (e) => { const {values} = this.props const idx = values.indexOf(this.selection) if (e.keyCode === 38 && idx > 0) { /* up */ this.selection = values[idx - 1] } else if (e.keyCode === 40 && idx < values.length -1) { /* down */ this.selection = values[idx + 1] } this.fireOnSelect() } fireOnSelect() { if (typeof this.props.onSelect === "function") this.props.onSelect(this.selection) /* solved! */ }}ReactDOM.render(

效果如下:

用同步的组件状态的机制没有出现意想不到的bug。

上面的代码片段不仅简洁美观,MobX还解决了setState的全部问题:

改变state马上就反映到了组件state上。这让代码逻辑和代码重用变得更简单。你不用去担心state是否更新了。

MobX在运行时候确定哪些state与视图层关联,暂时与视图层无关的State不会引起重新渲染,直到再次关联。

所以可渲染和不可渲染状态是统一处理的。

此外,直接修改state对象的低级错误不能再犯了。还有,不要担心是否还能用shouldComponentUpdate 和或者PureRenderMixin方法,MobX也很好的处理了。最后,你也许会想,我如何等到setState处理完成呢,你可以使用compentDidUpdate生命周期。

最后:

我已经停止使用React来管理组件状态了,而是用MobX代替。现在React成了“正真”的视图层:)。

以下是实现的Dome:

原文:

转载地址:http://ugkkx.baihongyu.com/

你可能感兴趣的文章
MyBatis 逆向工程
查看>>
iOS单例
查看>>
webpack 1.x 配合npm scripts管理多站点
查看>>
windows下Emacs的安装与配置
查看>>
CF Watto and Mechanism (字典树+深搜)
查看>>
【转】jQuery教程
查看>>
关于markdown怎么在博客园展示出来的问题
查看>>
bootstrap中的 form表单属性role="form"有什么作用?
查看>>
c#日期与字符串间的转换(转)
查看>>
Java基础(四)
查看>>
移动端禁止登陆
查看>>
Steve Jobs 2005年于 Stanford University 毕业典礼上的演讲
查看>>
java中枚举类的实际应用
查看>>
课程设计__C++初步,C++对C的扩充
查看>>
Codeforces 758A Holiday Of Equality
查看>>
P25、面试题1:赋值运算符函数
查看>>
Ajax详细介绍
查看>>
前端页面优化技巧
查看>>
python3爬虫-爬取58同城上所有城市的租房信息
查看>>
c/c++工程中的各种文件【转】
查看>>