假设我有一个依赖于另一个状态的状态(例如当A改变时,我希望B改变)。
创建一个观察a并在useEffect钩子中设置B的钩子是否合适?
效果是否会级联,当我点击按钮时,第一个效果会触发,导致b改变,导致第二个效果触发,在下一次渲染之前?这样构造代码在性能上有什么缺点吗?
let MyComponent = props => {
let [a, setA] = useState(1)
let [b, setB] = useState(2)
useEffect(
() => {
if (/*some stuff is true*/) {
setB(3)
}
},
[a],
)
useEffect(
() => {
// do some stuff
},
[b],
)
return (
<button
onClick={() => {
setA(5)
}}
>
click me
</button>
)
}
为了将来的目的,这可能也有帮助:
在useEffect中使用setState是可以的,你只需要注意不要创建一个循环。
但这并不是可能发生的唯一问题。见下文:
假设您有一个组件Comp,它从父组件接收props,并且根据props的变化您想要设置Comp的状态。出于某种原因,你需要在不同的useEffect中更改每个道具:
不要这样做
useEffect(() => {
setState({ ...state, a: props.a });
}, [props.a]);
useEffect(() => {
setState({ ...state, b: props.b });
}, [props.b]);
它可能永远不会改变a的状态,正如你在这个例子中看到的:
https://codesandbox.io/s/confident-lederberg-dtx7w
在本例中发生这种情况的原因是,当您更改两个道具时,两个useEffects运行在相同的react周期中。A和道具。B所以{…setState}在两个useEffect中是完全相同的,因为它们在同一个上下文中。当你运行第二个setState时,它将取代第一个setState。
而是这样做
这个问题的解决方案基本上是像这样调用setState:
useEffect(() => {
setState(state => ({ ...state, a: props.a }));
}, [props.a]);
useEffect(() => {
setState(state => ({ ...state, b: props.b }));
}, [props.b]);
在这里查看解决方案:https://codesandbox.io/s/mutable-surf-nynlx
现在,当您继续执行setState时,您总是会收到最新和正确的状态值。
useEffect可以钩住某个道具或状态。所以,为了避免无限循环钩子,你需要做的事情是绑定一些变量或状态到效果
例如:
useEffect(myeffectCallback, [])
上述效果只会在组件渲染后触发。这类似于componentDidMount生命周期
const [something, setSomething] = withState(0)
const [myState, setMyState] = withState(0)
useEffect(() => {
setSomething(0)
}, myState)
上面的效果只会触发我的状态已经改变,这与componentDidUpdate类似,只是不是每个改变的状态都会触发它。
你可以通过这个链接阅读更多细节