How to change Context value while using React Hook of useContext
How to update context with hooks is discussed in the How to avoid passing callbacks down? part of the Hooks FAQ.
The argument passed to createContext
will only be the default value if the component that uses useContext
has no Provider
above it further up the tree. You could instead create a Provider
that supplies the style
and visibility
as well as functions to toggle them.
Example
const { createContext, useContext, useState } = React;
const ThemeContext = createContext(null);
function Content() {
const { style, visible, toggleStyle, toggleVisible } = useContext(
ThemeContext
);
return (
<div>
<p>
The theme is <em>{style}</em> and state of visibility is
<em> {visible.toString()}</em>
</p>
<button onClick={toggleStyle}>Change Theme</button>
<button onClick={toggleVisible}>Change Visibility</button>
</div>
);
}
function App() {
const [style, setStyle] = useState("light");
const [visible, setVisible] = useState(true);
function toggleStyle() {
setStyle(style => (style === "light" ? "dark" : "light"));
}
function toggleVisible() {
setVisible(visible => !visible);
}
return (
<ThemeContext.Provider
value={{ style, visible, toggleStyle, toggleVisible }}
>
<Content />
</ThemeContext.Provider>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
You can use this approach, no matter how many nested components do you have it will work fine.
// Settings Context - src/context/Settings
import React, { useState } from "react";
const SettingsContext = React.createContext();
const defaultSettings = {
theme: "light",
};
export const SettingsProvider = ({ children, settings }) => {
const [currentSettings, setCurrentSettings] = useState(
settings || defaultSettings
);
const saveSettings = (values) => {
setCurrentSettings(values)
};
return (
<SettingsContext.Provider
value={{ settings: currentSettings, saveSettings }}
>
{children}
</SettingsContext.Provider>
);
};
export const SettingsConsumer = SettingsContext.Consumer;
export default SettingsContext;
// Settings Hook - src/hooks/useSettings
import { useContext } from "react";
import SettingsContext from "src/context/SettingsContext";
export default () => {
const context = useContext(SettingsContext);
return context;
};
// src/index
ReactDOM.render(
<SettingsProvider settings={settings}>
<App />
</SettingsProvider>,
document.getElementById("root")
// Any component do you want to toggle the theme from
// Example: src/components/Navbar
const { settings, saveSettings } = useSettings();
const handleToggleTheme = () => {
saveSettings({theme: "light"});
};