Using the useContext
hook with React 16.8+ works well. You can create a component, use the hook, and utilize the context values without any issues.
What I'm not certain about is how to apply changes to the Context Provider values.
1) Is the useContext hook strictly a means of consuming the context values?
2) Is there a recommended way, using React hooks, to update values from the child component, which will then trigger component re-rendering for any components using the useContext
hook with this context?
const ThemeContext = React.createContext({ style: 'light', visible: true }); function Content() { const { style, visible } = React.useContext(ThemeContext); const handleClick = () => { // change the context values to // style: 'dark' // visible: false } return ( <div> <p> The theme is <em>{style}</em> and state of visibility is <em> {visible.toString()}</em> </p> <button onClick={handleClick}>Change Theme</button> </div> ) }; function App() { return <Content /> }; const rootElement = document.getElementById('root'); ReactDOM.render(<App />, rootElement);
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.2/umd/react-dom.production.min.js"></script>
Using the useContext hook with React 16.8+ works well. You can create a component, use the hook, and utilize the context values without any issues.
Syntax: const authContext = useContext(initialValue); The useContext accepts the value provided by React. createContext and then re-render the component whenever its value changes but you can still optimize its performance by using memoization.
useContext. const value = useContext(MyContext); Accepts a context object (the value returned from React.createContext ) and returns the current context value for that context.
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" }); };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With