new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

React · Learn · all subjects

state/context

29 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Prop drilling problem and definition

Prop drilling occurs when you need to pass a prop through many intermediate components that don't use it, just to get it to a child component that needs it. This happens when you lift state up to a common ancestor that is far removed from the components needing the data, making props verbose and inconvenient to pass through the tree.

Context solves prop drilling without explicit prop passing

Context lets a parent component make information available to any component in the tree below it, no matter how deep, without passing it explicitly through props. This avoids the need to pass props through intermediate components that don't use them.

Three steps to use context

Using context requires three steps: (1) Create the context using createContext() and export it from a file. (2) Use the context in components that need it by calling useContext(ContextName). (3) Provide the context by wrapping children with a context provider component like <ContextName value={...}>{children}</ContextName>.

createContext default value argument

The only argument to createContext() is the default value, which React uses when no provider wraps the component reading the context. You can pass any kind of value as the default, including a number, string, object, or any other type.

useContext reads context from nearest provider

useContext is a Hook that reads context from the nearest context provider above in the component tree. If multiple providers of the same context exist at different levels, useContext returns the value from the closest one. You can only call useContext directly inside a React component, not inside loops or conditions.

Context provider syntax

To provide context, wrap children with the context component using the pattern: <ContextName value={someValue}>{children}</ContextName>. This tells React to make the value available to any component inside that asks for ContextName using useContext.

Component can use and provide the same context

A component can both read a context value using useContext and provide an updated value for that same context to its children. This allows components to build on context values from above, such as a Section component reading its parent's level and providing level + 1 to its children.

Context passes through intermediate components

Context automatically passes through intermediate components that don't use it. You can insert any number of components between a context provider and a component that consumes the context, including built-in components like div or custom components, without those intermediate components needing to know about the context.

Context enables components to adapt to surroundings

Context allows components to 'adapt to their surroundings' by reading context values and displaying themselves differently depending on where they are rendered in the tree. This is similar to CSS property inheritance where a value set on a parent affects all descendants unless explicitly overridden.

Different contexts don't override each other

Each context created with createContext() is completely separate from other contexts. Multiple contexts can be used in the same component without them interfering with each other. A component can use or provide many different contexts without problems.

Alternatives to context before using it

Before using context, consider: (1) Start by passing props directly - it makes data flow explicit and clear which components use which data. (2) Extract components and pass JSX as children - if data flows through intermediate components that don't use it, you may have missed extracting a component. If neither approach works well, then use context.

Common use cases for context

Context is useful for: (1) Theming - managing app appearance like dark mode in a context provider at the app top. (2) Current account - tracking logged-in user info accessible throughout the tree. (3) Routing - routing solutions commonly use context to hold the current route. (4) Managing complex state - combining a reducer with context to manage state and pass it down to distant components.

Context works with state for dynamic values

Context is not limited to static values. If you pass a different value on the next render, React will update all components reading it below. This is why context is often used together with state - state holds the value that is passed through context.

When to use context - distant components indicator

Context is a good solution when some information is needed by distant components in different parts of the tree. If many scattered components at various depths need the same data, it indicates that context will help.

LevelContext example creating context

To create a context, use: import { createContext } from 'react'; export const LevelContext = createContext(1); where 1 is the default value. Export it from a file so components can import and use it.

useContext hook example

To use context in a component: import { useContext } from 'react'; import { LevelContext } from './LevelContext.js'; export default function Heading({ children }) { const level = useContext(LevelContext); // ... use level value }

Context provider example

To provide context from a parent component: import { LevelContext } from './LevelContext.js'; export default function Section({ level, children }) { return ( <section className="section"> <LevelContext value={level}> {children} </LevelContext> </section> ); }

Using and providing context in same component example

A component can read context and provide an updated value to children: import { useContext } from 'react'; import { LevelContext } from './LevelContext.js'; export default function Section({ children }) { const level = useContext(LevelContext); return ( <section className="section"> <LevelContext value={level + 1}> {children} </LevelContext> </section> ); }

Creating separate contexts for state and dispatch

When combining a reducer with context, create two separate context objects: one for the state (e.g., TasksContext) and one for the dispatch function (e.g., TasksDispatchContext). Export both from a separate file so they can be imported elsewhere. Pass null as the default value; the actual values are provided by the component using the reducer.

Providing reducer state and dispatch via context

In the component using useReducer, wrap child components with the two context providers. The state context should have the tasks value, and the dispatch context should have the dispatch function. This makes both available to any component below in the tree.

Using context from child components

Child components can call useContext(TasksContext) to read the current state and useContext(TasksDispatchContext) to read the dispatch function. This allows them to read and update state without receiving these values as props, eliminating prop drilling.

TasksProvider component pattern

Create a custom provider component (e.g., TasksProvider) that accepts children as a prop and internally manages state with useReducer. The provider wraps children with both context providers, providing the reducer state and dispatch function to the tree. This centralizes all wiring in one reusable component.

Example: reducer with context - App component

import AddTask from './AddTask.js'; import TaskList from './TaskList.js'; import { TasksProvider } from './TasksContext.js'; export default function TaskApp() { return ( <TasksProvider> <h1>Day off in Kyoto</h1> <AddTask /> <TaskList /> </TasksProvider> ); }

Example: consuming dispatch context in child component

import { useState } from 'react'; import { useTasksDispatch } from './TasksContext.js'; export default function AddTask() { const [text, setText] = useState(''); const dispatch = useTasksDispatch(); return ( <> <input placeholder="Add task" value={text} onChange={e => setText(e.target.value)} /> <button onClick={() => { setText(''); dispatch({ type: 'added', id: nextId++, text: text, }); }}>Add</button> </> ); } let nextId = 3;

Example: consuming state context in child component

import { useState } from 'react'; import { useTasks, useTasksDispatch } from './TasksContext.js'; export default function TaskList() { const tasks = useTasks(); return ( <ul> {tasks.map(task => ( <li key={task.id}> <Task task={task} /> </li> ))} </ul> ); } function Task({ task }) { const [isEditing, setIsEditing] = useState(false); const dispatch = useTasksDispatch(); let taskContent; if (isEditing) { taskContent = ( <> <input value={task.text} onChange={e => { dispatch({ type: 'changed', task: { ...task, text: e.target.value } }); }} /> <button onClick={() => setIsEditing(false)}> Save </button> </> ); } else { taskContent = ( <> {task.text} <button onClick={() => setIsEditing(true)}> Edit </button> </> ); } return ( <label> <input type="checkbox" checked={task.done} onChange={e => { dispatch({ type: 'changed', task: { ...task, done: e.target.checked } }); }} /> {taskContent} <button onClick={() => { dispatch({ type: 'deleted', id: task.id }); }}> Delete </button> </label> ); }

Organizing reducer and context in a single file

Move the reducer function, context creation, provider component, and custom hooks into a single file to declutter the component files. Export the provider component and custom hooks from this file, keeping all wiring centralized. This makes the context setup reusable and keeps consuming components clean and focused.

useContext type inference in TypeScript

The type of the value provided by a context is inferred from the value passed to the createContext call. If there is no default value that makes sense, use null as the default and set the type as ContextShape | null.

useContext with null default value pattern

When using createContext with a null default value, the type should be ComplexObject | null. Create a custom Hook that checks for null existence and throws an error if the context is not present, allowing type consumers to use the non-null version of the type.

useContext TypeScript example with type narrowing

import { createContext, useContext, useState, useMemo } from 'react'; type ComplexObject = { kind: string }; const Context = createContext<ComplexObject | null>(null); const useGetComplexObject = () => { const object = useContext(Context); if (!object) { throw new Error("useGetComplexObject must be used within a Provider") } return object; } export default function MyApp() { const object = useMemo(() => ({ kind: "complex" }), []); return ( <Context.Provider value={object}> <MyComponent /> </Context.Provider> ) } function MyComponent() { const object = useGetComplexObject(); return ( <div> <p>Current object: {object.kind}</p> </div> ) }

Give your agent this brain