Context is a means to provide values from a component to all components that are contained within it - without explicitly passing it through all intermediate levels.
The interface of context can pass both data and event handlers
an application can have many different context types, e.g.:
ThemeContext
LanguageContext
UserContext
TodosContext
a component higher up in the component tree may provide a context
a component lower down may consume a context
(downwards dataflow, but with skipped intermediate levels)
possible structure with "stateful providers":
distinction of providers:
constate: library that creates a context with an associated state
defining the context:
custom hook that manages todo data:
function useTodos() {
// ...
return { todos, addTodo, deleteTodo, setTodoCompleted };
}
creating a provider component and a consumer hook:
const [TodosProvider, useTodosContext] = constate(useTodos);
providing the context:
function App() {
return (
<TodosProvider>
<AddTodoForm />
<TodoList />
<Statistics />
</TodosProvider>
);
}
querying the context:
function TodoList() {
const {
todos,
deleteTodo,
setTodoCompleted,
} = useTodosContext();
// ...
}
steps to provide context:
steps to query context:
useContext
in a componentdefining a context in JavaScript:
// ThemeContext.js
import { createContext } from 'react';
// default value: null
const ThemeContext = createContext(null);
export { ThemeContext };
A context always has a default / fallback value which will be used when no matching context provider is found
In TypeScript it can be cumbersome to define a default value to satisfy the type checker
defining a context type in TypeScript:
type ThemeContextType = {
theme: string;
onThemeChange: (theme: string) => void;
};
to satisfy the type checker when creating the context:
actually provide fallback values:
const ThemeContext = createContext<ThemeContextType>({
theme: 'light',
onThemeChange: () => {},
});
use null
and cast to any:
const ThemeContext = createContext<ThemeContextType>(
null as any
);
more information / solutions: React TypeScript cheatsheets
Example: using a "pure provider" (the state is in the App component)
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider
value={{ theme: theme, onThemeChange: setTheme }}
>
... sub-components ...
</ThemeContext.Provider>
);
}
example: product page with a "pure" context provider
function ProductPage() {
// ... (load product data from an API)
return (
<ProductContext.Provider value={productData}>
<ProductDescription />
<ProductPictures />
<ProductReviews />
<ProductQuestionsAndAnswers />
</ProductContext.Provider>
);
}
Example: creating a stateful provider that manages and provides state:
// TodosContext.tsx
function TodosProvider(props: { children: ReactNode }) {
const todosCtrl = useTodos();
<TodosContext.Provider value={todosCtrl}>
{props.children}
</TodosContext.Provider>;
}
function TodoApp() {
return <TodosProvider>...</TodosProvider>;
}
querying context from within a component:
const todosContext = useContext(TodosContext);