↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
- 在 react 18 版本以前在同步环境中异步,在异步环境中同步。
- 在 react 18 版本以后,setState()不论在同步环境还是异步环境都是异步的。
什么是状态撕裂?
- 如果
count在更新时,ComponentA和ComponentB渲染的时间不一致,可能会导致ComponentA显示旧状态,而ComponentB显示新状态,从而发生状态撕裂。 - 状态更新是异步的,React 的渲染也是异步的,这可能导致不同组件在不同时间渲染出不同的状态。
const CounterContext = createContext();
function App() {
const [count, setCount] = useState(0);
return (
<CounterContext.Provider value={{ count, setCount }}>
<ComponentA />
<ComponentB />
</CounterContext.Provider>
);
}
function ComponentA() {
const { count } = useContext(CounterContext);
return <div>ComponentA: {count}</div>;
}
function ComponentB() {
const { count } = useContext(CounterContext);
return <div>ComponentB: {count}</div>;
}
setState
有时异步有时同步
同步环境中异步
- 在 react 18 版本以前在同步环境中异步,在异步环境中同步。
- 在 react 18 版本以后,setState()不论在同步环境还是异步环境都是异步的。
export default class Ap extends Component {
state = {
a: 0
};
tap = () => {
this.setState(
{ a: this.state.a + 1 },
() => console.log(this.state.a, "能获取到最新值, 相当于 vue 的 nextTick")
);
console.log(this.state.a, "无法获取到最新值");
};
render() {
return (
<div className="App">
<h1 onClick={this.tap}>{this.state.a}</h1>
</div>
);
}
}
异步环境中同步
- 在 react 18 版本以前在同步环境中异步,在异步环境中同步。
- 在 react 18 版本以后,setState()不论在同步环境还是异步环境都是异步的。
export default class Ap extends Component {
state = {
a: 0
};
/**
* 在setTimeout 中是同步
*/
tap = () => {
setTimeout(() => {
this.setState({ a: this.state.a + 1 });
console.log(this.state.a, "--- 能获取到最新值");
});
};
/**
* 自定义dom事件中是同步
*/
componentDidMount() {
document.getElementById("h2")?.addEventListener("click", () => {
this.setState({ a: this.state.a + 1 });
console.log(this.state.a, "-- 能获取到最新值");
});
}
render() {
return (
<div className="App">
<h1 onClick={this.tap}>{this.state.a}</h1>
<h2 id="h2">{this.state.a}</h2>
</div>
);
}
}
同步中异步, 异步环境中同步
- 在 react 18 版本以前在同步环境中异步,在异步环境中同步。
- 在 react 18 版本以后,setState()不论在同步环境还是异步环境都是异步的。
// this.v 初始值为0
this.setState({ v: this.v + 1 })
this.setState({ v: this.v + 1 })
console.log(this.v) // 0
setTimeout(() => {
this.setState({ v: this.v + 1 })
console.log(this.v) // 2
this.setState({ v: this.v + 1 })
console.log(this.v) // 3
})
对象合并
合并的情况
export default class Ap extends Component {
state = {
a: 0
};
/**
* 三次setSate相当于一次
*/
tap = () => {
this.setState({ a: this.state.a + 1 });
this.setState({ a: this.state.a + 1 });
this.setState({ a: this.state.a + 1 });
};
render() {
return (
<div className="App">
<h1 onClick={this.tap}>{this.state.a}</h1>
</div>
);
}
}
不合并的写法
export default class Ap extends Component {
state = {
a: 0
};
tap = () => {
this.setState((state) => {
return { a: state.a + 1 };
});
this.setState((state) => {
return { a: state.a + 1 };
});
this.setState((state) => {
return { a: state.a + 1 };
});
};
render() {
return (
<div className="App">
<h1 onClick={this.tap}>{this.state.a}</h1>
</div>
);
}
}