STATE
state
import React, { Component } from 'react';
class Count extends Component{
constructor(props){
super(props);
this.state={count:0};
this.increase=this.increase.bind(this);
this.decrease=this.decrease.bind(this)
this.add=this.add.bind(this)
}
add(){
this.state.count=this.state.count+1
console.log(this.state.count)
}
increaseSelf(){
for(let i=0;i<1000;i++){
console.log(i)
this.setState({
count:this.state.count+1
})
}
}
increase(){
this.setState({
count:this.state.count+1
})
}
decrease(){
this.setState({
count:this.state.count-1
})
}
render(){
console.log('********组件渲染*********')
return(
<div style={{margin:"100px"}}>
<span>{this.state.count}</span>
<button onClick={this.add}>add</button>
<button onClick={this.increase}>increase</button>
<button onClick={this.increase}>decrease</button>
</div>
)
}
}
class App extends Component {
render() {
return (
<Count/>
);
}
}
export default App;
1.直接修改state,点击add按钮5次,依次打印1,2,3,4,5,但是页面上显示仍然是0,虽然修改了state,但不会渲染组件。
2.点击add按钮5次,一次打印1,2,3,4,5,页面上显示仍然是0,此时点击increase按钮,页面数字变成6.
修改increase()函数
increase(){
this.setState({
count:this.state.count+1
})
this.setState({
count:this.state.count+2
})
this.setState({
count:this.state.count+3
})
}
点击increase按钮,页面数字变成3。这是因为当前state.count的值是0,执行第一个setState()函数,将{count:0+1}映射到待执行队列,执行第二个setState()函数,将{count:0+2}映射到待执行队列,后执行的setState将覆盖掉前面的,最后一个是有效的。待执行队列中的count的值是3,执行更新。
如果改变三个setState()函数的顺序,最后一个有效。下列代码点击increase按钮,数字变成2
increase(){
this.setState({
count:this.state.count+1
})
this.setState({
count:this.state.count+3
})
this.setState({
count:this.state.count+2
})
修改increase()函数,点击increase按钮,数字变成6,执行前三个setState()函数时,最后一个有效,待执行队列中的count的值是3,当setState的参数是函数时,prevState的值从待执行队列中取得,所以最终结果是6。
increase(){
this.setState({
count:this.state.count+1
})
this.setState({
count:this.state.count+2
})
this.setState({
count:this.state.count+3
})
this.setState((prevState, props)=>{return{count:prevState.count+1}})
this.setState((prevState, props)=>{return{count:prevState.count+1}})
this.setState((prevState, props)=>{return{count:prevState.count+1}})
}
修改increase()函数,每点击一次,数字加1,不管点击速度有多快
increase(){
this.setState({
count:this.state.count+1
})
}
修改increase()函数
increase(){
this.increaseSelf()
}
从上面的两种情况可以猜测,待执行队列的执行时机,根据用户的行为,用户的一次操作,可能执行很多setState()函数,但是执行队列只执行一次。
修改increase()函数,点击increase按钮,数字变成2,setTimeout()也可以执行一次待执行队列(本质是setTimeout执行时,isBatchingUpdates是false)。实际上执行了两次render()函数。
increase(){
this.setState({
count:this.state.count+1
})
setTimeout(()=>this.setState({
count:this.state.count+1
}),0)
}
修改increase()函数,点击increase按钮,数字变成2,setTimeout()函数中的所有setState()都是同步执行,本质是isBatchingUpdates的值是false。
increase(){
setTimeout(()=>{
this.setState({
count:this.state.count+1
});
this.setState({
count:this.state.count+1
});
},0)
}
replaceState()和setState()的区别
比如现在state的结构是
state={
name:"Jack"
age:18
}
执行setState({name:"Tom"}),后
state={
name:"Tom"
age:18
}
如果执行的是replaceState({name:"Tom"})
state={
name:"Tom"
}
react中的事件是合成事件。其中就有事务对事件函数进行封装。
function method(){
console.log('111')
};
transaction.perform(method);
//执行initialize方法
//输出'111'
//执行close方法
**************************************************************************************************************
1.执行dispatchInteractiveEvent,此时isBatchingUpdates的值是false
function dispatchInteractiveEvent(topLevelType, nativeEvent) {
console.log('dispatchInteractiveEvent',isBatchingUpdates)//dispatchInteractiveEvent false
interactiveUpdates(dispatchEvent, topLevelType, nativeEvent);
}
2._interactiveUpdates函数就是interactiveUpdates$1函数
function interactiveUpdates(fn, a, b) {
return _interactiveUpdates(fn, a, b);
}
3.此时isBatchingUpdates的值是false,执行performWork(),isBatchingUpdates = true;finally最后执行,将isBatchingUpdates变成false,执行performSyncWork();更新内容。
function interactiveUpdates$1(fn, a, b) {
console.log('interactiveUpdates$1函数',isBatchingUpdates);//false
console.log(isBatchingInteractiveUpdates);//false
if (isBatchingInteractiveUpdates) {
return fn(a, b);
}
// If there are any pending interactive updates, synchronously flush them.
// This needs to happen before we read any handlers, because the effect of
// the previous event may influence which handlers are called during
// this event.
if (!isBatchingUpdates && !isRendering && lowestPendingInteractiveExpirationTime !== NoWork) {
// Synchronously flush pending interactive updates.
performWork(lowestPendingInteractiveExpirationTime, false, null);
lowestPendingInteractiveExpirationTime = NoWork;
}
var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;
var previousIsBatchingUpdates = isBatchingUpdates;
isBatchingInteractiveUpdates = true;
isBatchingUpdates = true;
try {
return fn(a, b);
} finally {
isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
}
}
}
4. dispatchEvent()调用batchedUpdates(),isBatching开始是false,执行_batchedUpdates()
var isBatching = false;
function batchedUpdates(fn, bookkeeping) {
console.log(isBatching);//false
console.log(isBatchingUpdates);//true
if (isBatching) {
// If we are currently inside another batch, we need to wait until it
// fully completes before restoring state.
return fn(bookkeeping);
}
isBatching = true;
try {
return _batchedUpdates(fn, bookkeeping);
} finally {
// Here we wait until all updates have propagated, which is important
// when using controlled components within layers:
// https://github.com/facebook/react/issues/1698
// Then we restore state of any controlled component.
isBatching = false;
var controlledComponentsHavePendingUpdates = needsStateRestore();
if (controlledComponentsHavePendingUpdates) {
// If a controlled event was fired, we may need to restore the state of
// the DOM node back to the controlled value. This is necessary when React
// bails out of the update without touching the DOM.
_flushInteractiveUpdates();
restoreStateIfNeeded();
}
}
}
经过一系列函数调用执行incease()函数,执行setState()函数
Component.prototype.setState = function (partialState, callback) {
!(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : void 0;
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};