Почему иногда render вызывается сразу после setState, а иногда нет
Вот мои коды:
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...
Я думаю, что функция рендеринга должна называться асинхронной, и на самом деле в большинстве случаев это так, например, когда я нажал первую кнопку, но когда я нажал вторую кнопку, функция рендеринга, кажется, называется синхронной, потому что журнал "after set state" печатается после журнала "render". почему это происходит?
1 ответ:
Таким образом, можно было бы подумать, чтоДумайте о setState () как о запросе, а не как о немедленной команде, чтобы обновите компонент. Для лучшей производительности, реагировать может задержите его, а затем обновите несколько компонентов за один проход. Реагировать не гарантирует, что изменения состояния будут применены немедленно. setState() не всегда сразу обновляет компонент. Это может быть пакетное обновление или отложить его на более поздний срок. Это делает чтение таким.государство сразу после звонка setState () потенциальная ловушка.
setStateявляется асинхронным. Но если мы посмотрим на некоторые ключевые слова, такие как:Так должны ли мы думать, чтоРеагировать может задержать его
Выполнении функция setState() не всегда немедленно обновить компонент.
Он может пакетировать или отложить обновление до более позднего времени.
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 будет обновлять состояние только асинхронно, когда react контролирует весь поток, где react не может контролировать поток, что означает, что контекст выполнения находится вне его, то react обновит состояние немедленно.
Что же тогда может взять под контроль react?
На самом деле вот небольшой фрагмент, чтобы удовлетворить наш эксперимент.
Такие вещи, какsetTimeout,setIntervalajax-запрос и другие webApi.
Даже обработчик событий, подключенный извне react, вызовет такое поведение.
У меня есть компонент ReactApp, который имеет состояние с ключомmyValueи метод с именемonClick.
Этот метод регистрирует текущее состояние, затем вызываетsetstate, а затем снова регистрирует состояние.
Appвизуализация 3 элементов:
- текущее значение
myValue.- кнопка, которую мы прикрепляем
onClickчерез react API.- кнопка, которую мы прикрепляем
onClickчерезaddEventListenerAPI (с другой стороны, не обращайте внимания).Когда мы нажимаем на первую кнопку, когда react контролирует поток, состояние обновляется асинхронно.
Когда мы нажмем вторую кнопку, react немедленно обновит состояние.
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'));<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>
Comments