React的Transaction浅析

1.两个示例

  • 示例1
let SonClass = React.createClass({
  render: function(){
    console.log("render", this.props.num);
    return null;
  },
  componentDidMount: function(){
    console.log('componentDidMount', this.props.num);
  }
});

let FatherClass = React.createClass({
  render:function(){

    return (
      <div>
        <SonClass num="one" />
        <SonClass num="two" />      
      </div>
    )
  }
});

ReactDOM.render( <FatherClass /> ,
    document.getElementById("test")
);

输出为
render *2
componentDidMount *2

  • 示例2
let React = require('react');
let ReactDOM = require('react-dom');

let Hello = React.createClass({
    getInitialState: function() {
        return {
            clicked: 0
        };
    },

    handleClick: function() {
        this.setState({
            clicked:this.state.clicked + 1
        });

        this.setState({
            clicked: this.state.clicked + 1
        });

            
    },

    render: function() {
        return <button onClick = {
            this.handleClick
        } > {
            this.state.clicked
        } </button>;
    }
});

ReactDOM.render( <Hello /> ,
    document.getElementById("test")
);

点击后this.state.clicked递增1,而不是递增2。

2.解释

首先介绍React的Transaction。
其源码在React/lib/Transaction.js。
Transaction就是给需要执行的方法fn用wrapper封装了 initialize 和 close 方法。且支持多次封装。再通过 Transaction 提供的 perform 方法执行。 perform执行前,调用所有initialize 方法。perform 方法执行后,调用所有close方法。

Transaction的use case是

  1. Preserving the input selection ranges before/after reconciliation.
    Restoring selection even in the event of an unexpected error.
  2. Deactivating events while rearranging the DOM, preventing blurs/focuses,
    while guaranteeing that afterwards, the event system is reactivated.
  3. Flushing a queue of collected DOM mutations to the main UI thread after a
    reconciliation takes place in a worker thread.
  4. Invoking any collected componentDidUpdate callbacks after rendering new
    content.
  5. (Future use case): Wrapping particular flushes of the ReactWorker queue
    to preserve the scrollTop (an automatic scroll aware DOM).
  6. (Future use case): Layout calculations before and after DOM updates.

示例一,对应的是第4点use case。整个生命周期就是一个Transaction,在Transaction执行期间,componentDidUpdate方法被推入一个队列中。DOM reconciliation后,再调用队列中的所有componentDidUpdate。

示例二,对应的是第3点use case。react的事件回调也是一个Transaction。handleClick里面的this.setState不会马上生效,而是先通过 ReactUpdates.batchedUpdate 方法存入临时队列。所以每次setState时,拿到的this.state.clicked都是初始值。直到transaction 完成,通过ReactUpdates.flushBatchedUpdates方法进行UI更新。
更详细的流程参考此图
react事件回调核心流程

3.参考文章(强烈推荐去看)

http://undefinedblog.com/what-happened-after-set-state/
http://zhuanlan.zhihu.com/purerender/20328570

posted @ 2015-12-06 23:36  草珊瑚  阅读(2128)  评论(1编辑  收藏  举报