为什么有时渲染会在setState之后立即调用,有时则不会

时间:2017-12-02 08:44:59

标签: javascript reactjs react-native

这是我的代码:

class TestState extends Component{
    constructor(props){
        super(props);
        this.state={
            text:"123"
        }
        this._hello = this._hello.bind(this)
    }

    _hello(){
        console.log("guangy will set state...");
        let num = Math.floor(Math.random()*100);
        this.setState({text: ""+num });
        console.log("guangy after set state...");
    }

    componentWillUpdate(){
        console.log("guangy componentWillUpdate")
    }

    render(){
        console.log("guangy render.....")
        return(<View>
            <Text>{this.state.text}</Text>
            <Button title="click" onPress={
                ()=>{
                    this._hello();
                }
            }/>
            <Button title="click1" onPress={
                ()=>{
                    setTimeout(()=>{
                        this._hello();
                    }, 10);
                }
            }/>
        </View>);
    }
}

当我点击第一个按钮时,日志为:

guangy will set state...
guangy after set state...
guangy componentWillUpdate
guangy render.....

并点击第二个按钮时记录日志:

guangy will set state...
guangy componentWillUpdate
guangy render.....
guangy after set state...

我认为渲染函数应该被称为异步,实际上在大多数情况下它就像我点击第一个按钮一样,但当我点击第二个按钮时,渲染函数似乎被称为同步,因为&# 34;经过设定状态&#34;在&#34;渲染&#34;之后打印日志。登录。为什么会这样?

1 个答案:

答案 0 :(得分:1)

根据DOCS

  

将setState()视为请求而不是立即命令   更新组件。为了获得更好的感知性能,React可能会   延迟它,然后一次更新几个组件。应对   不保证立即应用状态更改。   setState()并不总是立即更新组件。有可能   批量或推迟更新,直到稍后。这使得阅读this.state   在调用setState()之后就是一个潜在的陷阱。

所以人们会认为setState是异步的。但是,如果我们看一些关键词,如:

  

反应可能延迟

     

setState()不会始终立即更新组件。

     

MAY 批量处理或推迟更新,直到稍后。

那么我们是否认为setState可能是也可能不是异步操作? 好吧,是的。

这是setState取自源代码:

ReactComponent.prototype.setState = function(partialState, callback) {
  invariant(
    typeof partialState === 'object' ||
    typeof partialState === 'function' ||
    partialState == null,
    'setState(...): takes an object of state variables to update or a ' +
    'function which returns an object of state variables.'
  );
  this.updater.enqueueSetState(this, partialState);
  if (callback) {
    this.updater.enqueueCallback(this, callback, 'setState');
  }
};

看起来像一个普通的同步函数,实际上是setState因为它本身不是异步的,但它的执行效果可能是。

我自己做了一些测试,并且我意识到反应只会更新状态异步是反应控制整个流程,反应无法控制流程,这意味着执行上下文在它之外,然后react会立即更新状态。

那么可以采取什么反应控制呢? 诸如setTimeoutsetInterval ajax请求和其他webApi之类的内容 即使连接外部反应的事件处理程序也会触发此类行为。

事实上,这是一个可以满足我们实验的小片段 我有一个React组件App,其状态为myValue密钥,方法名为onClick
此方法记录当前状态,然后调用setstate然后再次记录状态。

App呈现3个元素:

  • myValue
  • 的当前值
  • 我们通过反应API附加onClick的按钮。
  • 我们通过onClick API附加addEventListener的按钮 (反思你的一面)。

当反应控制流时,当我们点击第一个按钮时,状态将异步更新。

当我们点击第二个按钮时,react会立即更新状态。

&#13;
&#13;
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      myVal: 0
    }
  }

  componentDidMount() {
    const el = document.getElementById('btn');
    el.addEventListener('click', this.onClick);
  }

  onClick = () => {
    console.log('Pre setState', this.state.myVal);
    this.setState({ myVal: this.state.myVal + 1 });
    console.log('Post setState', this.state.myVal);
    console.log('-------------------');
  }


  render() {
    const { myVal } = this.state;
    return (
      <div>
        <div>{myVal}</div>
        <button onClick={this.onClick}>Managed by react</button>
        <button id='btn'>Not Managed by react</button>
      </div>);
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
&#13;
&#13;
&#13;