博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Web 前端] 我不再使用React.setState的3个原因
阅读量:6451 次
发布时间:2019-06-23

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

copy from : 

 

从几个月前开始,我在新开发的React组件中不再使用setState。我并没有停止使用局部组件状态,只是不再用React来管理这些state,这是很不错的一个选择。

对于React初学者来说,使用setState是比较棘手的。即使是经验丰富的React开发者,在使用React本身的状态管理机制时,也经常会出现一些比较微妙的bug,例如:

忘记setState是异步的导致的bug:控制台的输出总是落后一项

React文档总结了使用setState时可能会出现的所有问题:

总的来说,使用setState有如下3个问题:

1、setState是异步的

很多开发者刚接触React时并没有注意到setState是异步的,如果你同时修改一些state,然后马上去调用某个state,得到的是之前的值,并不是修改后的。这是使用setState时最棘手的地方。如果在使用setState时没有注意到它是异步的,就会导致一些棘手的bug。

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(

乍一看,上面的代码并没有什么问题。两个事件处理函数(onKeyDown、onSelect)和一个功能函数(fireOnSelect)触发props的onSelect(如果存在)。上面的gif动态图很好的证明了Select组件的bug,当fireOnSelect被调用时,setState的操作并没有完成,因此,props的onSelect调用时传入的参数总是state中selection修改前的值。我认为React可以做的是将方法名重命名为scheduleState(注:我理解的意思是将方法置为调度状态,等setState操作完成后再执行)或者要求回调函数是必须的。

这个问题很容易修复,重点是要意识到这是个问题。

2018年1月25号注:。

2、setState会引起不必要的渲染(render)

setState的第二个问题是它会触发很多不必要的重新渲染。你可以使用React性能工具提供的方法监控什么时候触发了不必要的重新渲染。粗略地说,认为一次重新渲染是必要的有以下原因:

1)state新设置的值和上一次的值完全一样。这种情况通常可以通过实现shouldComponentUpdate生命周期来解决,或者你已经在使用一些库(pure render)来解决这个问题。

2)有时state的修改与UI显示相关,但也有些例外。比如一些state用于条件可见的UI时。

3)正如中提到的,一些实例状态与UI的展示完全不相关!通常一些是与管理事件监听器、计时器ID等相关的内部控制状态。

3、setState不足以管理所有的组件状态

正如上面2的最后一条所说,并不是所有组件状态都应该使用setState存储和更新。很多复杂组件通常需要使用生命周期函数来管理一些内容,例如:计时器、网络请求、事件等。使用setState管理这些复杂组件的状态不仅会触发重新渲染,还会导致一些相关的生命周期函数再次被触发,进而导致一些奇怪的状况。

使用MobX管理局部组件状态

(Surprise, surprise) 在,我们已经使用Mobx来管理所有的store。之前我们依然使用React的状态管理机制(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(

上面例子中的错误不会再出现:

使用同步的状态机制时,不会出现意外的错误

上面的示例代码不仅看起来更简洁,Mobx解决了所有setState相关的问题:

状态的更改会立即反映在局部组件状态中,这是我们的逻辑更简单,代码复用更容易,并且你不需要为状态尚未更新这一事实进行补偿(注:个人理解是需要额外的操作或代价)。

Mobx在运行时确定哪些可观察状态与UI渲染相关,暂时与UI无关的可观察状态不会导致组件的重新渲染,直到这些状态再次与UI相关。因此,将于UI无关的字段标记为@ observable(可观察状态)时,也不会出现上面提到的渲染代价或生命周期问题。

根据上面的解释,可渲染状态和不可渲染状态可以被统一管理。另外,存储在组件内部的状态和存储在store中的状态工作方式相同,可以达到一样的效果。这使得在必要时的组件重构、将组件内状态移动到单独的store或者将状态从store移动到组件内都很简单,在的教程中有演示。

Mobx有效地将组件转换为小型store。

此外,在使用可观察状态时,不会再出现直接给state赋值这样的低级错误。并且,我们不需要在为实现shouldComponentUpdate或PureRenderMixin而担忧,Mobx已经为我们解决了这个问题。最后,你可能会问,如果我想还使用setState并且等setState完成该怎么办,Mobx允许你仍然可以使用compentDidUpdate生命周期。

如何开始使用Mobx?

开始学习使用Mobx也十分简单,你可以或观看上面提到的视频。你可以简单地从你现有的代码中选取一个组件,使用@observer装饰它,并使用@observable引入一些可观察状态,你甚至不需要替换现有的setState调用,因为它们在使用Mobx时依然可以正常工作(虽然几分钟之内你就会感觉setState太繁琐,然后使用Mobx替换它)。如果你不喜欢使用装饰器也不需要担心,。

我已经在使用Mobx管理局部组件状态,不再使用React的setState,现在React是真正的’just the view’。在我的组件中,Mobx已经同时管理局部组件状态和store中的状态,它是简洁、同步、高效、统一的。从经验中,我感觉Mobx比React的setState更容易让React初学者理解。Mobx可以我们保持组件的简洁与简单。

: 使用setState管理状态

:使用Mobx管理状态

 

注:1、本文为翻译(@mweststrate)的文章,原文地址:

2、在我csdn的中有介绍Mobx的使用。

 

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

你可能感兴趣的文章
Request header is too large
查看>>
轮播插件swiper.js?
查看>>
网路流24题总结
查看>>
BZOJ-3732 Network 图论 最小生成树 倍增
查看>>
python之文件操作
查看>>
15 个 Android 通用流行框架大全
查看>>
Entity Framwork CodeFirst 学习笔记五:数据库映射的默认配置和设置
查看>>
ant 执行java文件,java文件中含中文,显示乱码
查看>>
IE8兼容@media和mp4视频的解决方案
查看>>
第二周总结
查看>>
ASP.NET完整打包卸载更新攻略(By Installshield 2010)
查看>>
[120_移动开发Android]006_android开发之数据存储之sdcard访问
查看>>
[若有所悟]IT小兵总结IT人特点及挽留IT人才的九大策略
查看>>
概率图模型建模、学习、推理资料总结
查看>>
【转】知道这20个正则表达式,能让你少写1,000行代码
查看>>
自定义 启动和关闭 oracle 的命令
查看>>
用ASP.NET Core 2.0 建立规范的 REST API
查看>>
SQLite数据库、ListView控件的使用
查看>>
Storm程序的并发机制(重点掌握)
查看>>
Quartz
查看>>