useEffect 挂钩在状态更改后不触发
useEffect Hook Not Firing After State Change
我有两个同级组件,它们在反应中通过上下文共享状态。
组件之间的共享状态是一个数组。
如果我在一个组件中更新 arr
状态,我希望另一个组件侦听该更新并相应地执行某些操作。当我在第二个组件中使用 useEffect
时,我会监听 arr
状态变量的变化。
例如:
// App Component -------
const App = props => {
const { arr, setArr } = useContext(GlobalContext)
const handleChange = () => {
const newArr = arr
[10, 20, 30, 40].map(v => {
newArr.push(v)
setArr(newArr)
})
return (...)
}
// App2 (Sibling) Component
const App2 = props => {
const { arr, setArr } = useContext(GlobalContext)
const [localArr, setLocalArr] = useState(0)
useEffect(
() => {
updateLocalState()
},
// fire if "arr" gets updated
[arr]
)
const updateLocalState = () => {
setLocalArr(localArr + 1)
}
return (...)
}
useEffect
挂钩 仅在 初始渲染时触发,尽管 arr
的状态会更新。
我知道向我的状态变量声明一个新变量const newArr = arr
是一个引用,所以newArr.push(v)
在技术上是一个状态突变。 然而,状态仍然更新,没有抛出警告,useEffect
什么也不做。
为什么 useEffect
虽然更新了状态但没有被调用?是因为状态突变吗?
第二个问题:为什么没有关于状态突变的警告或错误抛出?状态突变很危险 - 如果发生这种情况,我希望得到某种警告。
现场演示:
您作为第二个参数传递给 useEffect
的数组仅检查数组中的元素是否 ===
到先前渲染中的元素。 const newArr = arr;
将导致 newArr === arr
,因为它不会创建新数组,这不是您想要的。
使用 arr
中的所有元素创建一个新数组,它将按预期工作。
const App = props => {
const { arr, setArr } = useContext(GlobalContext)
const handleChange = () => {
const newArr = [...arr]
[10, 20, 30, 40].forEach(v => {
newArr.push(v)
})
setArr(newArr)
}
return <>{/* ... */}</>
}
当您想使用 useState 钩子更新数组时。确保将数组扩展到新数组并更新新数组,以便调用侦听此状态的 useEffect。
UseEffect 不会在下面的代码片段中调用,因为您正在直接更新数组。
const [skills, selectedSkills] = useState([])
const onSelect = (selectedList) => {
selectedSkills(selectedList)
}
useEffect(() => {
MyLogger('useEffect called')
}, [skills])
UseEffect 将在下面的代码片段中调用,因为我们正在保持对数组的新引用。
const [skills, selectedSkills] = useState([])
const onSelect = (selectedList) => {
const tempSelectedList = [...selectedList]
selectedSkills(tempSelectedList)
}
useEffect(() => {
MyLogger('useEffect called')
}, [skills])
我有两个同级组件,它们在反应中通过上下文共享状态。 组件之间的共享状态是一个数组。
如果我在一个组件中更新 arr
状态,我希望另一个组件侦听该更新并相应地执行某些操作。当我在第二个组件中使用 useEffect
时,我会监听 arr
状态变量的变化。
例如:
// App Component -------
const App = props => {
const { arr, setArr } = useContext(GlobalContext)
const handleChange = () => {
const newArr = arr
[10, 20, 30, 40].map(v => {
newArr.push(v)
setArr(newArr)
})
return (...)
}
// App2 (Sibling) Component
const App2 = props => {
const { arr, setArr } = useContext(GlobalContext)
const [localArr, setLocalArr] = useState(0)
useEffect(
() => {
updateLocalState()
},
// fire if "arr" gets updated
[arr]
)
const updateLocalState = () => {
setLocalArr(localArr + 1)
}
return (...)
}
useEffect
挂钩 仅在 初始渲染时触发,尽管 arr
的状态会更新。
我知道向我的状态变量声明一个新变量const newArr = arr
是一个引用,所以newArr.push(v)
在技术上是一个状态突变。 然而,状态仍然更新,没有抛出警告,useEffect
什么也不做。
为什么 useEffect
虽然更新了状态但没有被调用?是因为状态突变吗?
第二个问题:为什么没有关于状态突变的警告或错误抛出?状态突变很危险 - 如果发生这种情况,我希望得到某种警告。
现场演示:
您作为第二个参数传递给 useEffect
的数组仅检查数组中的元素是否 ===
到先前渲染中的元素。 const newArr = arr;
将导致 newArr === arr
,因为它不会创建新数组,这不是您想要的。
使用 arr
中的所有元素创建一个新数组,它将按预期工作。
const App = props => {
const { arr, setArr } = useContext(GlobalContext)
const handleChange = () => {
const newArr = [...arr]
[10, 20, 30, 40].forEach(v => {
newArr.push(v)
})
setArr(newArr)
}
return <>{/* ... */}</>
}
当您想使用 useState 钩子更新数组时。确保将数组扩展到新数组并更新新数组,以便调用侦听此状态的 useEffect。
UseEffect 不会在下面的代码片段中调用,因为您正在直接更新数组。
const [skills, selectedSkills] = useState([])
const onSelect = (selectedList) => {
selectedSkills(selectedList)
}
useEffect(() => {
MyLogger('useEffect called')
}, [skills])
UseEffect 将在下面的代码片段中调用,因为我们正在保持对数组的新引用。
const [skills, selectedSkills] = useState([])
const onSelect = (selectedList) => {
const tempSelectedList = [...selectedList]
selectedSkills(tempSelectedList)
}
useEffect(() => {
MyLogger('useEffect called')
}, [skills])