I was trying to use React's context and I faced the following issues. I am new to react, so bear with me and would appreciate if you can direct me to a useful resource
<ParentComponentProvider>
<ChildComponent />
</ParentComponentProvider>
import React, { createContext, useContext } from 'react';
const MyContext = createContext();
const ParentComponentProvider = ({ children }) => {
return (
<MyContext.Provider value="Hello from context">
{children}
</MyContext.Provider>
);
};
const ChildComponent = () => {
const contextValue = useContext(MyContext);
return <div>{contextValue}</div>;
};
const App = () => {
return (
<div>
<ChildComponent />
</div>
);
};
Does a component has to be wrapped inside of a provider to be able to access the values of the context?
To access the value
passed to <MyContext.Provder>
, yes
will the following childComponent be able to access the context even if it's not wrapped inside of a provider
You would only be able to access any default context values, ie the value you pass to createContext()
...
const MyContext = createContext("This is the default message");
Does a change in a value of a context affect the components that are wrapped inside of a provider to re-render?
If those components use the context via the useContext()
hook, then yes; the hook triggers a re-render when changes are detected.
If there are wrapped components that do not use the hook, they will not. This is why it's generally ok to wrap your entire application in a context provider
what if I don't wrap the components that use the contextvalues inside of a provider, will they re-render?
No. Again, they will only be able to access the default context value which is not changing.
Consider the following context and provider
const MyContext = createContext({ value: "Default context value"});
const MyContextProvider = ({ children }) => {
const [value, setValue] = useState("Initial context value");
return (
<MyContext.Provider value={{ value, setValue }}>
{children}
</MyContext.Provider>
);
};
<MyContextProvider>
will only see "Default context value"setValue()
with a new value, it and the other wrapped consumers will re-render and see the new value.Here's a more involved demo showing what happens
const MyContextConsumer = ({ id }) => {
const { value } = useContext(MyContext);
console.log(`[MyContextConsumer::${id}] Render!`);
return <p>{value}</p>;
};
const MyContextUpdater = () => {
const { setValue } = useContext(MyContext);
console.log("[MyContextUpdater] Render!");
return (
<button onClick={() => setValue(`New value ${Date.now()}`)}>
Update context value
</button>
);
};
const SomeComponent = () => {
console.log("[SomeComponent] Render!");
return <p>Static content</p>;
};
with a top-level like this
<MyContextProvider>
<MyContextConsumer id="in-provider" />
<MyContextUpdater />
<SomeComponent />
</MyContextProvider>
<MyContextConsumer id="outside-provider" />
You would see on initial render
[MyContextConsumer::in-provider] Render!
[MyContextUpdater] Render!
[SomeComponent] Render!
[MyContextConsumer::outside-provider] Render!
On clicking the button, you would then see
[MyContextConsumer::in-provider] Render!
[MyContextUpdater] Render!