Considering a situation where I have an App component, and Contexts components, called 'AuthContext' and 'usersAndProductsContext'.
In the context components I have few states, which are initialized in App component and from there will be given to other components to share the states like so:
return (
<div className="App">
<usersAndProductsContext.Provider
value={{
usersVal: usersVal,
productsVal: productsVal,
toggle_pressed_login_flag: toggle_pressed_login_flag,
handleAddUser: handleAddUser,
}}
>
<AuthContext.Provider
value={{
isLoggedIn: isLoggedIn,
edit_currentLoggedUserId: edit_currentLoggedUserId,
currentLoggedUserId: currentLoggedUserId,
isLoggedInEditVal: isLoggedInEditVal,
}}
>
<Routes>
<Route exact path="/" element={<Login />} />
<Route exact path="farmers" element={<Farmers />} />
<Route exact path="customer" element={<Customer />} />
<Route exact path="register" element={<Register />} />
<Route exact path="farmershop/:id" element={<Farmer />} />
<Route exact path="mystore/" element={<MyStore />} />
</Routes>
</AuthContext.Provider>
</usersAndProductsContext.Provider>
</div>
);
when I pass to other components, as I did using 'Provider', it means I'm sharing with all other components these states which are given within the 'value' prop.
Does that mean that every change of the passed-on-using-provider states, in other component, will mean that the information which was passed on in all components has now changed? Or did it become some sort of local copy?
To emphasize what I mean:
function MyStore() {
let authCtx = useContext(AuthContext);
let usersAndItemsCtx = useContext(usersAndProductsContext);
...
if I change usersAndItemsCtx from MyStore, will it mean that all other component's state that I have changed?
Hope it made sense?
Regards!
CodePudding user response:
It depends on what you mean by change. If you mean mutating
the state then no, but if you mean update the state then yes.
If you do authCtx.someProperty = false;
, then do not expect the other components to rerender. The actual way to update the context would by passing a setter function down the context and using it.
Looking at this, there seems to be a handleAddUser
, if this is called and it updates the context only then a change will reflected in other components.
value={{
usersVal: usersVal,
productsVal: productsVal,
toggle_pressed_login_flag: toggle_pressed_login_flag,
handleAddUser: handleAddUser,
}}
Here is a sandbox where I have mutated the context. Note, how the setInterval
logs the mutated value but there is no update to the UI because the component never rerendered. These kind of bugs are common when mutating state (or context by extension).
The relevant code:
const TextContext = createContext();
function App() {
const [text, setText] = useState({
val: "string",
count: 0
});
return (
<>
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<TextContext.Provider value={[text, setText]}>
<Wrapper />
</TextContext.Provider>
</div>
</>
);
}
function Wrapper(props) {
return (
<div style={{ padding: "20px" }}>
<TextControlWithHook />
<br />
<Random />
</div>
);
}
function Random() {
const [text, setText] = useContext(TextContext);
const mutateContext = () => {
text.val = "1231232";
};
return <button onClick={mutateContext}>MUTATE</button>;
}
function TextControlWithHook(props) {
const [text, setText] = useContext(TextContext);
useEffect(() => {
console.log("outside", { text });
const id = setInterval(() => {
console.log(text);
}, 5000);
return () => clearInterval(id);
}, [text]);
return (
<input
className="form-control"
value={text.val}
onChange={(e) => {
const val = e.target.value;
setText((text) => ({ ...text, val }));
}}
/>
);
}