setState()更新状态的两种写法
-
setState(updater,[callback])
updater 为返回stateChange的函数的对象,(state,props) => stateChange
接收的state和props被保证为最新的
函数方式:
1、如果新状态依赖于原状态 this.setState((state,props) => ({ count: state.count+1 }),()=>{ // callback }) -
setState(stateChange,[callback])
stateChange为对象
callback是可选的回调函数,在状态更新且界面更新后才执行
对象方式:
1、新状态不依赖于原状态 ==>使用对象方式
this.setState({count:this.state.count+1},()=>{
// callback
})
案例
<body>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
<div id="root"></div>
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count:0
}
}
test1 = ()=> {
// 如果新状态依赖于原状态,使用函数方式
this.setState((state,props)=> ({
count: state.count+1
}))
console.log('test1之后获取count的值:',this.state.count); // 0
}
test2 = ()=> {
// 新状态不依赖于原状态 ==>使用对象方式
const count = this.state.count + 1;
this.setState({count});
console.log('test2之后获取count的值:',this.state.count);
}
test3 = ()=> {
this.setState(state =>({
count: state.count + 1
}),()=>{
console.log('test3-----setState回调函数中count的值:',this.state.count);
})
}
render() {
return (
<div>
<h1>A组件:{this.state.count}</h1>
<button onClick={this.test1}>测试1</button><br />
<button onClick={this.test2}>测试2</button><br />
<button onClick={this.test3}>测试3</button><br />
</div>
)
}
}
ReactDOM.render(<App />,document.getElementById('root'));
</script>
</body>
setState的同步与异步
setState()内部是利用的 “事务” 实现异步更新状态
同步
定时器,DOM事件监听回调,Promise
异步
在react控制的回调函数中:生命周期钩子 、 react事件监听的回调
异步的setState() 多次调用,如何处理?
注意:异步情况
- setState({}): 合并更新一次状态,只调用一次render()更新界面 --- 状态更新和界面更新都合并了
- setState(fn): 更新多次状态,但只调用一次render更新界面, ----状态更新没有合并但界面更新合并了
- 先执行setState({}) 对象方式再执行**setState(fn)**函数方式,状态更新没有合并,但界面更新合并了
得到异步更新后的状态数据
在setState()的callback回调函数中
案例
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
<div id="root"></div>
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count:0
}
}
/**
* react事件监听相关的回调中:- setState()是异步更新状态的
*/
test1 = ()=> {
console.log('setSate回调函数之前---react事件监听回调',this.state.count);
this.setState(state=>({
count:state.count+1
}))
console.log('setSate回调函数之后---react事件监听回调',this.state.count);
}
/**
* react生命周期钩子中:- setState()是异步更新状态的
*/
componentDidMount() {
console.log('setSate回调函数之前---生命周期钩子',this.state.count);
this.setState(state=>({
count:state.count+1
}))
console.log('setSate回调函数之后--生命周期钩子',this.state.count);
}
// 同步 (定时器,DOM事件监听回调,Promise)
test2 = ()=> {
setTimeout(() => {
console.log('setSate回调函数之前---定时器',this.state.count);
this.setState(state=>({
count:state.count+1
}))
console.log('setSate回调函数之后---定时器',this.state.count);
}, 0);
}
test4 = () => {
const btn4 = this.refs.btn4;
btn4.onclick = ()=> {
console.log('setSate回调函数之前---原生DOM',this.state.count);
this.setState(state=>({
count:state.count+1
}))
console.log('setSate回调函数之后---原生DOM',this.state.count);
}
}
test3 = ()=> {
Promise.resolve().then(res => {
console.log('setSate回调函数之前---Promise',this.state.count);
this.setState(state=>({
count:state.count+1
}))
console.log('setSate回调函数之后---Promise',this.state.count);
})
}
test5 = ()=> {
console.log('setState 函数方式 - 1 --调用前',this.state.count);
this.setState(state => ({
count: state.count+1
}))
console.log('setState 函数方式 - 1 --调用后',this.state.count);
this.setState(state => ({
count: state.count+1
}))
console.log('setState 函数方式 - 2 --调用后',this.state.count);
}
test6 = ()=> {
console.log('setState 对象方式 - 1 --调用前',this.state.count);
this.setState({count:this.state.count+1});
console.log('setState 对象方式 - 1 --调用后',this.state.count);
this.setState({count:this.state.count+1});
console.log('setState 对象方式 - 2 --调用后',this.state.count);
}
test7 = () => {
console.log('setState 对象方式 - 1 --调用前',this.state.count);
this.setState({count:this.state.count+1});
console.log('setState 对象方式 - 1 --调用后',this.state.count);
this.setState(state => ({
count: state+1
}));
console.log('setState 函数方式 - 1 --调用后',this.state.count);
}
render() {
return (
<div>
<h1>A组件:{this.state.count}</h1>
<button onClick={this.test1}>测试1</button><br />
<button onClick={this.test2}>测试2</button><br />
<button onClick={this.test3}>Promise</button><br />
<button ref="btn4" onClick={this.test4}>原生DOM</button><br />
<button onClick={this.test5}>setState多次调用---函数方式</button><br />
<button onClick={this.test6}>setState多次调用---对象方式</button><br />
<button onClick={this.test7}>setState多次调用---对象方式和函数方式</button><br />
</div>
)
}
}
ReactDOM.render(<App />,document.getElementById('root'));
</script>
setState()常见的面试题
如果上面讲解的内容都能理解的,下面的内容很容易的。🙂
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
<div id="root"></div>
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count:0
}
}
/**
* Promise和定时器相比,promise会先执行
* setState()执行一次,导致数据发生变化,就会触发render的更新
*/
componentDidMount() {
this.setState({count:this.state.count+1});
this.setState({count:this.state.count+1});
console.log('1----',this.state.count); // 2 --> 0(上面两个会被合并成一个)
this.setState(state => ({
count: state.count+1
}))
this.setState(state => ({
count: state.count+1
}))
console.log('2-----',this.state.count); // 3 --> 0 (第四次执行,输出结果为3)
setTimeout(() => {
this.setState({count:this.state.count+1});
console.log('timeout-1',this.state.count); // 8 ---> 6
this.setState({count:this.state.count+1});
console.log('timeout-2',this.state.count); // 10 ---> 7
}, 0);
Promise.resolve().then(value=>{
this.setState({count:this.state.count+1});
console.log('promise-1',this.state.count); // 5 --> 4
this.setState({count:this.state.count+1});
console.log('promise-2',this.state.count); // 7 --> 5
})
}
render() {
const count = this.state.count;
console.log('render',count); // 1 --- 0 , 4 ---> 3, 6 ---> 4 , 9 ---> 6,11 --> 7
return (
<div>
<h1>A组件:{this.state.count}</h1>
</div>
)
}
}
ReactDOM.render(<App />,document.getElementById('root'));
</script>