I have a state declaration in my application that holds an array
of information and can be updated by a form nested within a sub-component.
I'm using useState
s callback syntax in order to update the data, but for some reason, despite the callback running and the state changing, it won't be updated.
This can be confirmed when checking a state change in useEffect
; it won't output any changes with a console.log
. However, inside the callback itself, the console.log
will work every time (so clearly the callback is running).
This is a simplified layout of what I'm doing:
const MainContext = createContext();
const Parent = () => {
const [data, setData] = useState([]);
const updateData = (index, field, value) => {
// This just updates (or initialises) an object at the specified index.
setData(previousState => {
let candidates = previousState;
let candidate = candidates[index];
if(typeof candidate !== "object"){
candidate = {};
}
candidate[field] = value;
candidates[index] = candidate;
// This will run every time, and return the correct result:
// [{
// example: value
// }]
console.log(candidates);
return candidates;
});
};
useEffect(() => {
console.log(data); // This will not run whenever the field is updated.
}, [data]);
return (
<MainContext.Provider value={{
dispatch: {
updateData
}
}}>
<Child />
</MainContext.Provider>
);
};
// Whenever a user enters data inside this components input, it should push a change
// via the dispatch.updateData method and update the array in the parent component.
const Child = () => {
const testIndex = 1;
return (
<MainContext.Consumer>{({ dispatch }) => (
<input
name="example"
placeholder="Example Field"
onChange={evt => dispatch.updateData(
testIndex,
evt.target.name,
evt.target.value
)} />
)}</MainContext.Consumer>
);
};
So, what's going on here? It appears the state is being set correctly, and even if I wrap the updateData
method into a useCallback
with the deps set to the state hook, it will still fail to console out in the useEffect
.