React中setState同步更新策略

setState 同步更新

创新互联公司是一家集网站建设,鹰潭企业网站建设,鹰潭品牌网站建设,网站定制,鹰潭网站建设报价,网络营销,网络优化,鹰潭网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。

我们在上文中提及,为了提高性能React将setState设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于this.state来计算未来状态。典型的譬如我们希望在从服务端抓取数据并且渲染到界面之后,再隐藏加载进度条或者外部加载提示:

 
 
 
 
  1. componentDidMount() { 
  2.     fetch('https://example.com') 
  3.         .then((res) => res.json()) 
  4.         .then( 
  5.             (something) => { 
  6.                 this.setState({ something }); 
  7.                 StatusBar.setNetworkActivityIndicatorVisible(false); 
  8.             } 
  9.         ); 

因为setState函数并不会阻塞等待状态更新完毕,因此setNetworkActivityIndicatorVisible有可能先于数据渲染完毕就执行。我们可以选择在componentWillUpdate与componentDidUpdate这两个生命周期的回调函数中执行setNetworkActivityIndicatorVisible,但是会让代码变得破碎,可读性也不好。实际上在项目开发中我们更频繁遇见此类问题的场景是以某个变量控制元素可见性:

 
 
 
 
  1. this.setState({showForm : !this.state.showForm}); 

我们预期的效果是每次事件触发后改变表单的可见性,但是在大型应用程序中如果事件的触发速度快于setState的更新速度,那么我们的值计算完全就是错的。本节就是讨论两种方式来保证setState的同步更新。

完成回调

setState函数的第二个参数允许传入回调函数,在状态更新完毕后进行调用,譬如:

 
 
 
 
  1. this.setState({ 
  2.      load: !this.state.load, 
  3.      count: this.state.count + 1 
  4.    }, () => { 
  5.      console.log(this.state.count); 
  6.      console.log('加载完成') 
  7.    }); 

这里的回调函数用法相信大家很熟悉,就是JavaScript异步编程相关知识,我们可以引入Promise来封装setState:

 
 
 
 
  1. setStateAsync(state) { 
  2.     return new Promise((resolve) => { 
  3.       this.setState(state, resolve) 
  4.     }); 
  5.   } 

setStateAsync 返回的是Promise对象,在调用时我们可以使用Async/Await语法来优化代码风格:

 
 
 
 
  1. async componentDidMount() { 
  2.    StatusBar.setNetworkActivityIndicatorVisible(true) 
  3.    const res = await fetch('https://api.ipify.org?format=json') 
  4.    const {ip} = await res.json() 
  5.    await this.setStateAsync({ipAddress: ip}) 
  6.    StatusBar.setNetworkActivityIndicatorVisible(false) 
  7.  } 

这里我们就可以保证在setState渲染完毕之后调用外部状态栏将网络请求状态修改为已结束,整个组件的完整定义为:

 
 
 
 
  1. class AwesomeProject extends Component { 
  2.   state = {} 
  3.   setStateAsync(state) { 
  4.     ... 
  5.   } 
  6.   async componentDidMount() { 
  7.    ... 
  8.   } 
  9.   render() { 
  10.     return ( 
  11.        
  12.          
  13.           My IP is {this.state.ipAddress || 'Unknown'} 
  14.          
  15.        
  16.     ); 
  17.   } 

传入状态计算函数

除了使用回调函数的方式监听状态更新结果之外,React还允许我们传入某个状态计算函数而不是对象来作为***个参数。状态计算函数能够为我们提供可信赖的组件的State与Props值,即会自动地将我们的状态更新操作添加到队列中并等待前面的更新完毕后传入***的状态值:

 
 
 
 
  1. this.setState(function(prevState, props){  
  2. return {showForm: !prevState.showForm}  
  3. }); 

这里我们以简单的计数器为例,我们希望用户点击按钮之后将计数值连加两次,基本的组件为:

 
 
 
 
  1. class Counter extends React.Component{ 
  2.   constructor(props){ 
  3.     super(props); 
  4.     this.state = {count : 0}  
  5.     this.incrementCount = this.incrementCount.bind(this) 
  6.   } 
  7.   incrementCount(){ 
  8.     ... 
  9.   } 
  10.   render(){ 
  11.     return 
     
  12.               Increment 
  13.               
    {this.state.count}
     
  14.           
 
  •   } 
  • 直观的写法我们可以连续调用两次setState函数,这边的用法可能看起来有点怪异,不过更多的是为了说明异步更新带来的数据不可预测问题。

     
     
     
     
    1. incrementCount(){ 
    2.    this.setState({count : this.state.count + 1})  
    3.    this.setState({count : this.state.count + 1}) 
    4.  } 

    上述代码的效果是每次点击之后计数值只会加1,实际上第二个setState并没有等待***个setState执行完毕就开始执行了,因此其依赖的当前计数值完全是错的。我们当然可以使用上文提及的setStateAsync来进行同步控制,不过这里我们使用状态计算函数来保证同步性:

     
     
     
     
    1. incrementCount(){ 
    2.   this.setState((prevState, props) => ({ 
    3.      count: prevState.count + 1 
    4.    })); 
    5.   this.setState((prevState, props) => ({ 
    6.      count: prevState.count + 1 
    7.    })); 
    8.  } 

    这里的第二个setState传入的prevState值就是***个setState执行完毕之后的计数值,也顺利保证了连续自增两次。

    【本文是专栏作者“张梓雄 ”的原创文章,如需转载请通过与作者联系】

    戳这里,看该作者更多好文

    网页名称:React中setState同步更新策略
    文章网址:http://www.zyruijie.cn/qtweb/news21/12121.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

    猜你还喜欢下面的内容

    外贸网站建设知识

    各行业网站