首頁  >  文章  >  web前端  >  React中setState使用詳解

React中setState使用詳解

php中世界最好的语言
php中世界最好的语言原創
2018-05-24 14:19:008652瀏覽

這次帶給大家React中setState使用詳解,React中setState使用的注意事項有哪些,下面就是實戰案例,一起來看一下。

拋出問題

class Example extends Component {
  contructor () {
    super()
    this.state = {
      value: 0,
      index: 0
    }
  }
  componentDidMount () {
    this.setState({value: this.state.value + 1})
    console.log(this.state.value) // 第一次输出
    this.setState({value: this.state.value + 1})
    console.log(this.state.value) // 第二次输出
    setTimeout(() => {
      this.setState({value: this.state.value + 1})
      console.log(this.state.value) // 第三次输出
      this.setState({value: this.state.value + 1})
      console.log(this.state.value) // 第四次输出
    }, 0);
        this.refs.button.addEventListener('click', this.click)
  }
  click = () => {
    this.setState({value: this.state.index + 1})
    this.setState({value: this.state.index + 1})
  }
  render () {
    return (
      <p><span>value: {this.state.value}index: {this.props.index}</span>
        <button>点击</button>
      </p>
    )
  }
}
  • 這四次輸出,以常理來說分別是: 1,2,3,4。但是,實際輸出為: 0, 0, 2, 3

setState的注意點

  1. setState不會立刻改變React元件中state的值(即setState是非同步更新)

  • setState透過一個佇列機制實作state更新;

  • #當執行setState時,會將需要更新的state合併後放入狀態佇列,而不會立即更新,佇列可以有效率的批次更新state;

  • 透過this.state直接修改的值,state不會放入狀態佇列,下次呼叫setState並對狀態佇列進行合併時,會忽略先前直接被修改的state.

  • setState透過引發一次元件的更新過程來引發重新繪製

    • 此處重繪指的就是造成React的更新生命週期函數4個函數:

    • shouldComponentUpdate(被呼叫時this.state沒有更新;如果回傳了false,生命週期被中斷,雖然不呼叫之後的函數了,但是state仍然會被更新)

    • #componentWillUpdate(呼叫時this.state沒有更新)

    • render(被呼叫時this.state被更新)

    • componentDidUpdate

  • 多個相鄰的state的修改可能會合併到一起一次執行

  •  this.setState({name: 'Pororo'})
     this.setState({age: 20})
    • 等同於

     this.setState({name: 'Pororo',age: 20})
    • 上面兩塊程式碼的效果是一樣的。如果每次呼叫都引發一次生命週期更新,那麼效能就會消耗很大了。所以,React會將多個this.setState產生的修改放進一個佇列裡,等差不多的時候就會引發一次生命週期更新。

    問題分析

    • 對於前兩次setState:

    this.setState({value: this.state.val + 1});
    console.log(this.state.value); // 第一次输出
    this.setState({value: this.state.val + 1});
    console.log(this.state.value); // 第二次输出
    • 由於setState不會立即改變React元件中state的值,所以兩次setState中this.state.value都是同一個值0,故而,這兩次輸出都是0。因而value只加1。

    • 既然這樣,那是不是可以直接操作this.state呢?例如:this.state.value=this.state.value 1;

    • 這樣的確可以修改this.state.value的狀態但是卻不可以引發重複渲染。

    • 所以,就必須透過React設定的setState函數去改變this.state,進而引發重新渲染。

    • setTimeout裡面的兩次setState:

    #
    setTimeout(() => {
      this.setState({value: this.state.value + 1})
      console.log(this.state.value) // 第三次输出
      this.setState({value: this.state.value + 1})
      console.log(this.state.value) // 第四次输出
    }, 0);
    • ##這兩次this.state的值同步更新了;

    • 同步更新:是由React引發的事件處理(例如:onClick引發的事件處理),呼叫setState會異步更新this.state;

    • 非同步更新:除此之外的setState呼叫會同步執行this.setState。 「除此之外」指的是:繞過React透過addEventListener直接加入的事件處理函數和setTimeout/setInterval產生的非同步呼叫。

    • this.setState更新機製圖解:

    React中setState使用詳解

    • #每次setState產生新的state會依序存入一個佇列,然後會根據isBathingUpdates變數判斷是直接更新this.state還是放進dirtyComponent裡回頭再說。

    • isBatchingUpdates預設是false,也就表示setState會同步更新this.state。

    • 但是,当React在调用事件处理函数之前就会调用batchedUpdates,这个函数会把isBatchingUpdates修改为true,造成的后果就是由React控制的事件处理过程setState不会同步更新this.state。

    同步更新(函数式setState)

    1. 如果this.setState的参数不是一个对象而是一个函数时,这个函数会接收到两个参数,第一个是当前的state值,第二个是当前的props,这个函数应该返回一个对象,这个对象代表想要对this.state的更改;

    2. 换句话说,之前你想给this.setState传递什么对象参数,在这种函数里就返回什么对象。不过,计算这个对象的方法有些改变,不再依赖于this.state,而是依赖于输入参数state。

    function increment(state, props) {
      return {count: state.count + 1};
    }
    function incrementMultiple() {
      this.setState(increment);
      this.setState(increment);
      this.setState(increment);
    }
    • 假如当前this.state.count的值是0,第一次调用this.setState(increment),传给increment的state参数是0,第二调用时,state参数是1,第三次调用是,参数是2,最终incrementMultiple让this.state.count变成了3。

    • 对于多次调用函数式setState的情况,React会保证调用每次increment时,state都已经合并了之前的状态修改结果。

    要注意的是,在increment函数被调用时,this.state并没有被改变,依然,要等到render函数被重新执行时(或者shouldComponentUpdate函数返回false之后)才被改变。

    同步异步setState的用法混合

    function incrementMultiple() {
      this.setState(increment);
      this.setState(increment);
      this.setState({count: this.state.count + 1});
      this.setState(increment);
    }
    • 在几个函数式setState调用中插入一个传统式setState调用,最后得到的结果是让this.state.count增加了2,而不是增加4。

    • 这是因为React会依次合并所有setState产生的效果,虽然前两个函数式setState调用产生的效果是count加2,但是中间出现一个传统式setState调用,一下子强行把积攒的效果清空,用count加1取代。

    • 所以,传统式setState与函数式setState一定不要混用。

    相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

    推荐阅读:

    JS中使用接口步骤详解

    EasyCanvas绘图库在Pixeler项目开发中使用实战总结

    以上是React中setState使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn