Original Question
I am trying to learn more about the inner workings of React, and here specifically Context Providers so I don't have a use-case in mind, just trying to understand why it works the way it does.
In my context.tsx I wondering why the logged state.value is the static initial value and does not reflect the current value saved therein (see comments in the file below)
import React, { createContext, useState } from "react";
interface myState {
value: number;
setValue: Function;
}
export const MyContext = createContext<myState | null>(null);
export const MyContextProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const setValue = (newVal: number) => {
console.log(state.value); // why is this static?
setState((prevState) => {
// prevState does contain the value it currently holds
return {
...prevState,
value: newVal,
};
});
};
const [state, setState] = useState({
value: 10, // whatever is entered here is what will be logged above
setValue: setValue,
});
return <MyContext.Provider value={state}>{children}</MyContext.Provider>;
};
Here's a CodeSandbox with the above file in an app: https://codesandbox.io/p/sandbox/inspiring-pike-9972nf
EDIT
Thanks to https://stackoverflow.com/a/79437349/5086312 I've seen that changing the return value to
return (
<MyContext.Provider
value={{
...state,
// if this line is commented out the console log above
// will show the initial value, else it shows the current
setValue: setValue,
}}
>
{children}
</MyContext.Provider>
);
Will produce the expected output, however commenting out the indicated line breaks the behaviour. This almost feels like some sort of compiler bug. Notice that having state.value is not actually needed inside the value={...}.
const [value, setValue] = useState(10)andvalue={{ value, setValue }}value={{...state}}andvalue={{...state, setValue: setValue,}}causestate.valueto be different in the console log