React State and Lifecycle文档that state updates may be asynchronous中警告我们。因此,我们不应依赖于它们的值来计算下一个状态:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment
})
相反,我们应该使用setState
的函数更新形式来确保我们具有正确的state先前值:
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}))
此示例适用于可在函数回调中引用整个状态的类组件。
在定义函数组件时,我们可以为状态设置单独的值,如下所示:
function MyComponent() {
const [a, setA] = useState(1)
const [b, setB] = useState(2)
}
大概应用了相同的异步规则,这就是setA
钩子提供的useState
函数也接受函数参数更新的原因,就像这样:
function MyComponent() {
const [a, setA] = useState(1)
const [b, setB] = useState(2)
const onClick = () => {
setA(a => a + 1)
}
return <>
<div>a: {a}</div>
<div>b: {b}</div>
<button onClick={onClick}>Update a</button>
</>
}
当我们想基于a
的值更新b
时会发生什么?基于状态更新异步的早期问题,我们不想直接引用b
,而是使用set state的函数版本来接收其值。
这可以通过将我们所有的状态放到这样的单个对象上来实现:
function MyComponent() {
const [state, setState] = useState({ a: 1, b: 2 })
const onClick = () => {
setState(state => ({ b: state.b, a: state.a + state.b }))
}
return <>
<div>a: {state.a}</div>
<div>b: {state.b}</div>
<button onClick={onClick}>Update a based on b</button>
</>
}
这对我来说很有意义。
我的问题是:使用钩子时,使用如上所述的组合对象(或useReducer
)是基于多个其他状态值更新状态值的唯一适当且安全的方法吗?>
或者像这样通过闭包引用变量是否合适(我不正确):
function MyComponent() {
const [a, setA] = useState(1)
const [b, setB] = useState(2)
const onClick = () => {
setA(a => a + b)
}
return <>
<div>a: {a}</div>
<div>b: {b}</div>
<button onClick={onClick}>Update a</button>
</>
}
还是其他方式?
编辑:
更多的挖掘工作,我发现了Dan Abramov React UI as a Runtime - Batching的这篇博客文章。在其中,他建议使用useReducer
处理复杂的状态更新情况:
当状态逻辑变得比几个setState调用复杂时,我建议使用
useReducer
挂钩将其表示为本地状态缩减器。
所以也许是组合状态对象或useReducer
是这种方式。
答案 0 :(得分:2)
这就是React.useEffect
发挥作用的地方:
import React from "react";
import "./styles.css";
export default function App() {
const [a, setA] = React.useState();
const [b, setB] = React.useState();
const [c, setC] = React.useState();
React.useEffect(() => {
setA(5);
setB(5);
}, []);
React.useEffect(() => setC(a + b), [a, b]);
return (
<div className="App">
<h1>{c}</h1>
</div>
);
}
正在渲染组件时,第一个React.useEffect
设置a和b。
第二个React.useEffect
根据a和b设置c,并且将更改以下依赖项之一(a
或b
)时将触发它。