React中setState同步更新策略
2017-08-11 17:14
295 查看
React中setState同步更新策略从属于笔者的Web
前端入门与工程实践中的React入门与最佳实践系列总纲系列文章,推荐阅读2016-我的前端之路:工具化与工程化。
我们在上文中提及,为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于this.state来计算未来状态。典型的譬如我们希望在从服务端抓取数据并且渲染到界面之后,再隐藏加载进度条或者外部加载提示:
因为setState函数并不会阻塞等待状态更新完毕,因此setNetworkActivityIndicatorVisible有可能先于数据渲染完毕就执行。我们可以选择在componentWillUpdate与componentDidUpdate这两个生命周期的回调函数中执行setNetworkActivityIndicatorVisible,但是会让代码变得破碎,可读性也不好。实际上在项目开发中我们更频繁遇见此类问题的场景是以某个变量控制元素可见性:
我们预期的效果是每次事件触发后改变表单的可见性,但是在大型应用程序中如果事件的触发速度快于setState的更新速度,那么我们的值计算完全就是错的。本节就是讨论两种方式来保证setState的同步更新。
setState函数的第二个参数允许传入回调函数,在状态更新完毕后进行调用,譬如:
这里的回调函数用法相信大家很熟悉,就是JavaScript异步编程相关知识,我们可以引入Promise来封装setState:
setStateAsync 返回的是Promise对象,在调用时我们可以使用Async/Await语法来优化代码风格:
这里我们就可以保证在setState渲染完毕之后调用外部状态栏将网络请求状态修改为已结束,整个组件的完整定义为:
除了使用回调函数的方式监听状态更新结果之外,React还允许我们传入某个状态计算函数而不是对象来作为第一个参数。状态计算函数能够为我们提供可信赖的组件的State与Props值,即会自动地将我们的状态更新操作添加到队列中并等待前面的更新完毕后传入最新的状态值:
这里我们以简单的计数器为例,我们希望用户点击按钮之后将计数值连加两次,基本的组件为:
直观的写法我们可以连续调用两次setState函数,这边的用法可能看起来有点怪异,不过更多的是为了说明异步更新带来的数据不可预测问题。
上述代码的效果是每次点击之后计数值只会加1,实际上第二个setState并没有等待第一个setState执行完毕就开始执行了,因此其依赖的当前计数值完全是错的。我们当然可以使用上文提及的setStateAsync来进行同步控制,不过这里我们使用状态计算函数来保证同步性:
这里的第二个setState传入的prevState值就是第一个setState执行完毕之后的计数值,也顺利保证了连续自增两次。
转载https://zhuanlan.zhihu.com/p/24781259?refer=wxyyxc1992
前端入门与工程实践中的React入门与最佳实践系列总纲系列文章,推荐阅读2016-我的前端之路:工具化与工程化。
setState 同步更新
我们在上文中提及,为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于this.state来计算未来状态。典型的譬如我们希望在从服务端抓取数据并且渲染到界面之后,再隐藏加载进度条或者外部加载提示:componentDidMount() { fetch('https://example.com') .then((res) => res.json()) .then( (something) => { this.setState({ something }); StatusBar.setNetworkActivityIndicatorVisible(false); } ); }
因为setState函数并不会阻塞等待状态更新完毕,因此setNetworkActivityIndicatorVisible有可能先于数据渲染完毕就执行。我们可以选择在componentWillUpdate与componentDidUpdate这两个生命周期的回调函数中执行setNetworkActivityIndicatorVisible,但是会让代码变得破碎,可读性也不好。实际上在项目开发中我们更频繁遇见此类问题的场景是以某个变量控制元素可见性:
this.setState({showForm : !this.state.showForm});
我们预期的效果是每次事件触发后改变表单的可见性,但是在大型应用程序中如果事件的触发速度快于setState的更新速度,那么我们的值计算完全就是错的。本节就是讨论两种方式来保证setState的同步更新。
完成回调
setState函数的第二个参数允许传入回调函数,在状态更新完毕后进行调用,譬如:this.setState({ load: !this.state.load, count: this.state.count + 1 }, () => { console.log(this.state.count); console.log('加载完成') });
这里的回调函数用法相信大家很熟悉,就是JavaScript异步编程相关知识,我们可以引入Promise来封装setState:
setStateAsync(state) { return new Promise((resolve) => { this.setState(state, resolve) }); }
setStateAsync 返回的是Promise对象,在调用时我们可以使用Async/Await语法来优化代码风格:
async componentDidMount() { StatusBar.setNetworkActivityIndicatorVisible(true) const res = await fetch('https://api.ipify.org?format=json') const {ip} = await res.json() await this.setStateAsync({ipAddress: ip}) StatusBar.setNetworkActivityIndicatorVisible(false) }
这里我们就可以保证在setState渲染完毕之后调用外部状态栏将网络请求状态修改为已结束,整个组件的完整定义为:
class AwesomeProject extends Component { state = {} setStateAsync(state) { ... } async componentDidMount() { ... } render() { return ( <View style={styles.container}> <Text style={styles.welcome}> My IP is {this.state.ipAddress || 'Unknown'} </Text> </View> ); } }
传入状态计算函数
除了使用回调函数的方式监听状态更新结果之外,React还允许我们传入某个状态计算函数而不是对象来作为第一个参数。状态计算函数能够为我们提供可信赖的组件的State与Props值,即会自动地将我们的状态更新操作添加到队列中并等待前面的更新完毕后传入最新的状态值:this.setState(function(prevState, props){ return {showForm: !prevState.showForm} });
这里我们以简单的计数器为例,我们希望用户点击按钮之后将计数值连加两次,基本的组件为:
class Counter extends React.Component{ constructor(props){ super(props); this.state = {count : 0} this.incrementCount = this.incrementCount.bind(this) } incrementCount(){ ... } render(){ return <div> <button onClick={this.incrementCount}>Increment</button> <div>{this.state.count}</div> </div> } }
直观的写法我们可以连续调用两次setState函数,这边的用法可能看起来有点怪异,不过更多的是为了说明异步更新带来的数据不可预测问题。
incrementCount(){ this.setState({count : this.state.count + 1}) this.setState({count : this.state.count + 1}) }
上述代码的效果是每次点击之后计数值只会加1,实际上第二个setState并没有等待第一个setState执行完毕就开始执行了,因此其依赖的当前计数值完全是错的。我们当然可以使用上文提及的setStateAsync来进行同步控制,不过这里我们使用状态计算函数来保证同步性:
incrementCount(){ this.setState((prevState, props) => ({ count: prevState.count + 1 })); this.setState((prevState, props) => ({ count: prevState.count + 1 })); }
这里的第二个setState传入的prevState值就是第一个setState执行完毕之后的计数值,也顺利保证了连续自增两次。
转载https://zhuanlan.zhihu.com/p/24781259?refer=wxyyxc1992
相关文章推荐
- React的异步更新的setState
- 震惊! React中三个方法获取setState更新之后的state !其中一个竟用到Promise!
- appstore更新后 网站同步策略
- 分布式系统中一些主要的副本更新策略——Dynamo/Cassandra/Riak同时采取了主从式更新的同步+异步类型,以及任意节点更新的策略。
- setState 同步更新
- React总结1:异步更新的setState
- 使用 SVN post-commit 钩子同步更新代码 经常会忽略的问题
- 实现不同数据库同步更新数据
- android解决:使用多线程和Handler同步更新UI
- Linux(CentOS) SVN服务器搭建+同步更新+多版本库+开机启动
- C++控制台通迅录系统,实现文件同步更新
- android应用版本更新策略
- quick-cocos2d-x基于源码加密打包功能的更新策略
- silverlight 数据库更新,UI控件同步更新
- tomcat集群环境下,JSP页面更新同步,页面展示未更新 的问题排查
- 让电脑文档同步更新的新服务
- Xcode4 自动同步更新 svn Bundle version
- 自己寻思的手机游戏更新策略
- myeclipse 中 svn 更新 提交 同步资源库 详细解释下他们的功能