I have two sibling components that share state via context in react. The shared state between the components is an array.
If I update arr
state in one component, I want the other component to listen for that update and do something accordingly. When I use useEffect
in the second component, I listen for changes in the arr
state variable.
For example:
// 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 (...)
}
The useEffect
hook is only fired on the initial render, though the state of arr
updates.
I know that declaring a new variable const newArr = arr
to my state variable is a reference, so newArr.push(v)
is technically a state mutation. However, the state still updates, no warning is thrown, and useEffect
does nothing.
Why does useEffect
not get called though the state gets updated? Is it because of the state mutation?
Second Question: Why is there no warning or error thrown regarding a state mutation? State mutations are dangerous - If it happens, I'd expect some sort of warning.
Live demo here:
The array you pass as second argument to useEffect
only checks if the elements in the array are ===
to the elements in it in the previous render. const newArr = arr;
will lead to newArr === arr
since it doesn't create a new array, which is not what you want.
Create a new array with all the elements in arr
and it will work as expected.
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 <>{/* ... */}</>
}
When you want to update array using useState hook. Make sure to spread the array into new array and update the new array so that your useEffect listening for this state will be called.
UseEffect will not call in the below code snippet as you are directly updating array.
const [skills, selectedSkills] = useState([])
const onSelect = (selectedList) => {
selectedSkills(selectedList)
}
useEffect(() => {
MyLogger('useEffect called')
}, [skills])
UseEffect will call in the below code snippet as we are keeping new reference to the array.
const [skills, selectedSkills] = useState([])
const onSelect = (selectedList) => {
const tempSelectedList = [...selectedList]
selectedSkills(tempSelectedList)
}
useEffect(() => {
MyLogger('useEffect called')
}, [skills])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.