Context Hooks - rs-hash/Senior GitHub Wiki
useContext is a React Hook that lets you read and subscribe to context from your component.
import { useContext } from 'react';
function MyComponent() {
const theme = useContext(ThemeContext);
// ...
SomeContext: The context that you’ve previously created with createContext. The context itself does not hold the information, it only represents the kind of information you can provide or read from components.
useContext returns the context value for the calling component. It is determined as the value passed to the closest SomeContext.Provider
above the calling component in the tree. If there is no such provider, then the returned value will be the defaultValue you have passed to createContext for that context. The returned value is always up-to-date. React automatically re-renders components that read some context if it changes.
- useContext() always looks for the closest provider above the component that calls it. It searches upwards and does not consider providers in the component from which you’re calling useContext().
- Overriding context for a part of the tree -You can override the context for a part of the tree by wrapping that part in a provider with a different value.
<ThemeContext.Provider value="dark">
...
<ThemeContext.Provider value="light">
<Footer />
</ThemeContext.Provider>
...
</ThemeContext.Provider>
- Optimizing re-renders when passing objects and functions -You can pass any values via context, including objects and functions.
// Before
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
function login(response) {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}
return (
<AuthContext.Provider value={{ currentUser, login }}>
<Page />
</AuthContext.Provider>
);
}
Here, the context value is a JavaScript object with two properties, one of which is a function. Whenever MyApp re-renders (for example, on a route update), this will be a different object pointing at a different function, so React will also have to re-render all components deep in the tree that call useContext(AuthContext).
In smaller apps, this is not a problem. However, there is no need to re-render them if the underlying data, like currentUser, has not changed. To help React take advantage of that fact, you may wrap the login function with useCallback and wrap the object creation into useMemo. This is a performance optimization:
// After
import { useCallback, useMemo } from 'react';
function MyApp() {
const [currentUser, setCurrentUser] = useState(null);
const login = useCallback((response) => {
storeCredentials(response.credentials);
setCurrentUser(response.user);
}, []);
const contextValue = useMemo(() => ({
currentUser,
login
}), [currentUser, login]);
return (
<AuthContext.Provider value={contextValue}>
<Page />
</AuthContext.Provider>
);
}
In smaller apps, this is not a problem. However, there is no need to re-render them if the underlying data, like currentUser, has not changed. To help React take advantage of that fact, you may wrap the login function with useCallback and wrap the object creation into useMemo. This is a performance optimization:
import { useState, createContext, useContext } from "react";
import Form from "./Form";
const ThemeContext = createContext(null);
export const useThemeContext = () => useContext(ThemeContext);
const Parent = () => {
const [theme, setTheme] = useState("dark");
return (
<ThemeContext.Provider value={theme}>
<h2>Welcome to theme example</h2>
<Form />
<input
type="checkbox"
checked={theme === "dark"}
onChange={(e) => {
setTheme(e.target.checked ? "dark" : "light");
}}
/>
</ThemeContext.Provider>
);
};
export default Parent;
// Form
import { useThemeContext } from "./Example3";
const Form = () => {
const currentTheme = useThemeContext();
return (
<>
<div
style={
currentTheme === "dark"
? { backgroundColor: "black" }
: { backgroundColor: "white" }
}
>
<h2
style={
currentTheme === "dark" ? { color: "white" } : { color: "black" }
}
>
Form{" "}
</h2>
</div>
</>
);
};
export default Form;