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/basics

63 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

State definition and purpose

In React, state is data that changes over time. You can add state to any component and update it as needed. State allows components to respond to user input and display different output over time.

Principle: Make state as simple as it can be

The goal of good state structure is to make state easy to update without introducing mistakes. Remove redundant and duplicate data from state to help ensure that all pieces stay in sync. This is similar to how database engineers normalize database structures to reduce bugs. As Albert Einstein said: 'Make your state as simple as it can be--but no simpler.'

Example: Use ID instead of duplicate object state

```js import { useState } from 'react'; const initialItems = [ { title: 'pretzels', id: 0 }, { title: 'crispy seaweed', id: 1 }, { title: 'granola bar', id: 2 }, ]; export default function Menu() { const [items, setItems] = useState(initialItems); const [selectedId, setSelectedId] = useState(0); const selectedItem = items.find(item => item.id === selectedId); function handleItemChange(id, e) { setItems(items.map(item => { if (item.id === id) { return { ...item, title: e.target.value }; } else { return item; } })); } return ( <> <h2>What's your travel snack?</h2> <ul> {items.map((item) => ( <li key={item.id}> <input value={item.title} onChange={e => handleItemChange(item.id, e)} /> <button onClick={() => setSelectedId(item.id)}>Choose</button> </li> ))} </ul> <p>You picked {selectedItem.title}.</p> </> ); } ``` Store only the selectedId in state instead of the selectedItem object itself, then find the selected item during render. This eliminates duplication when items are updated.

Example: Removing redundant fullName state

```js import { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const fullName = firstName + ' ' + lastName; function handleFirstNameChange(e) { setFirstName(e.target.value); } function handleLastNameChange(e) { setLastName(e.target.value); } return ( <> <h2>Let's check you in</h2> <label> First name: <input value={firstName} onChange={handleFirstNameChange} /> </label> <label> Last name: <input value={lastName} onChange={handleLastNameChange} /> </label> <p>Your ticket will be issued to: <b>{fullName}</b></p> </> ); } ``` Instead of storing fullName in state, calculate it during render from firstName and lastName.

Group related state that changes together

If two or more state variables always update together, merge them into a single state variable. For example, use a single position object with x and y properties instead of separate x and y state variables. This prevents them from getting out of sync.

Do not store redundant calculated values in state

If you can calculate some information from component props or existing state variables during rendering, do not put that information into component state. Calculate it during render instead. For example, calculate fullName from firstName and lastName during each render rather than storing fullName as a separate state variable.

Avoid contradictory state

Structure state to prevent impossible states. For example, if isSending and isSent should never both be true, use a single status state variable with valid values like 'typing', 'sending', or 'sent' instead of separate boolean variables.

Example: Avoiding contradictory state with status variable

```js import { useState } from 'react'; export default function FeedbackForm() { const [text, setText] = useState(''); const [status, setStatus] = useState('typing'); async function handleSubmit(e) { e.preventDefault(); setStatus('sending'); await sendMessage(text); setStatus('sent'); } const isSending = status === 'sending'; const isSent = status === 'sent'; if (isSent) { return <h1>Thanks for feedback!</h1> } return ( <form onSubmit={handleSubmit}> <p>How was your stay at The Prancing Pony?</p> <textarea disabled={isSending} value={text} onChange={e => setText(e.target.value)} /> <br /> <button disabled={isSending} type="submit">Send</button> {isSending && <p>Sending...</p>} </form> ); } function sendMessage(text) { return new Promise(resolve => { setTimeout(resolve, 2000); }); } ``` This replaces isSending and isSent booleans with a single status state variable that can be 'typing', 'sending', or 'sent', preventing impossible states where both are true simultaneously.

Flatten deeply nested state

Deeply hierarchical state is inconvenient to update. When possible, prefer to structure state in a flat way. For nested hierarchies, instead of storing nested objects with childPlaces arrays, store a normalized structure where each item has an id and references to child IDs, and maintain a lookup object mapping IDs to items (like a database table).

Avoid duplication in state

When the same data is stored in multiple places in state, it becomes difficult to keep them in sync. If you have information duplicated between multiple state variables or within nested objects, reduce the duplication. For UI patterns like selection, store only the ID or index in state instead of the entire object.

Do not mirror props into state

Storing a prop value directly in state causes them to get out of sync when the parent component passes a new value. The state is only initialized during the first render and won't update when the prop changes. Use the prop directly in your code instead. Only mirror props into state with 'initial' or 'default' prefix if you intentionally want to ignore prop updates.

Lift state up to share between components

To make multiple components share and update state together, move the state from the individual components upwards to the closest parent component containing all of them. Then pass the state and handler function down to the child components as props. This is called lifting state up.

Props pass data from parent to child

Props are information you pass down from a parent component to child components. You pass props using JSX syntax with curly braces, just like you would with built-in HTML attributes. Child components receive props as parameters and can read them.

State-driven UI: describe visual states instead of direct DOM commands

With React, you don't modify the UI from code directly by writing commands like 'disable the button' or 'show the success message'. Instead, you describe the UI you want to see for different visual states of your component ('initial state', 'typing state', 'success state'), then trigger state changes in response to user input. This approach is similar to how designers think about UI.

Example: Context for heading levels

import { createContext, useContext } from 'react'; export const LevelContext = createContext(0); function Section({ children }) { const level = useContext(LevelContext); return ( <section className="section"> <LevelContext value={level + 1}> {children} </LevelContext> </section> ); } function Heading({ children }) { const level = useContext(LevelContext); switch (level) { case 1: return <h1>{children}</h1>; case 2: return <h2>{children}</h2>; case 3: return <h3>{children}</h3>; default: throw Error('Unknown level: ' + level); } } This example shows using context to determine heading levels based on nesting depth without passing props.

Context.Provider component passes value to children

Wrap components in ContextObject.Provider or Context.Provider component with a value prop to pass context data down to child components. All descendants of the provider can access that context value.

useContext retrieves value from nearest Context provider

Use useContext(ContextObject) to read the current value of a context from the nearest provider of that context in the component tree. The component must be inside a provider of that context to read the value.

createContext creates a context object

Use createContext to create a context object. Pass the default value as an argument. For example, `export const LevelContext = createContext(0);` creates a context with a default value of 0.

Lifting state up: share state between sibling components

To keep the state of two components in sync, remove state from both of them, move it to their closest common parent component, and then pass it down via props. This is known as 'lifting state up' and is one of the most common patterns in React. For example, if only one panel should be active at a time, the parent component holds the activeIndex state and passes isActive and onShow props to child panels.

Avoid redundant or duplicate state in components

State should not contain redundant or duplicated information. If there is unnecessary state derived from other state variables, it is easy to forget to update it and introduce bugs. For example, a fullName state variable is redundant if firstName and lastName already exist—instead calculate fullName during rendering.

Use state instead of trying to change props for interactivity

When you need to respond to user input or change what a component displays, you must use state, not modify props. Props are read-only. To learn how to add interactivity, refer to State: A Component's Memory.

Types of state change triggers

State updates are triggered by two kinds of inputs: human inputs (clicking a button, typing in a field, navigating a link) and computer inputs (network response arriving, timeout completing, image loading). You must set state variables to update the UI in response to either type of input.

Avoiding paradoxes by removing non-essential state

Ask these questions about state variables: (1) Does this state cause a paradox? (e.g., isTyping and isSubmitting can't both be true—combine into a status variable with specific values). (2) Is the same information available in another state variable already? (e.g., isEmpty and isTyping can't both be true—remove isEmpty and check answer.length === 0). (3) Can you get the same information from the inverse of another state variable? (e.g., remove isError and check error !== null instead). Reducing redundant state variables prevents bugs and keeps components easier to understand.

Identifying visual states

Enumerate all the different visual states your component can display. Similar to how designers create mockups for different visual states, you should visualize and list each state the component might be in. For example, a form might have states: Empty, Typing, Submitting, Success, and Error. This helps ensure the component handles all scenarios correctly.

Lifting state up three-step process

To lift state up between two components that need to coordinate: (1) Remove state from the child components, (2) Pass hardcoded data from the common parent component, (3) Add state to the common parent and pass it down together with event handlers.

Controlled vs uncontrolled components

An uncontrolled component has some local state and its parent cannot influence that state. A controlled component has its important information driven by props rather than its own local state, letting the parent component fully specify its behavior. Uncontrolled components are easier to use within parents but less flexible when coordinating multiple components. Controlled components are maximally flexible but require parents to fully configure them with props.

Single source of truth for state

For each unique piece of state in a React application, choose one specific component that owns it. This is the single source of truth principle. Instead of duplicating shared state between components, lift it up to their common shared parent and pass it down to children that need it. It is common to move state up or down while figuring out where each piece of state should live.

Lifting state example: Accordion with Panel components

This example shows lifting state in an Accordion component that manages two Panel child components. The Accordion stores activeIndex state and passes isActive props and onShow event handlers to each Panel. When activeIndex is 0, the first panel is active (isActive={true}); when it's 1, the second panel is active. Only one panel is expanded at a time.

Controlled Panel component final implementation

The Panel component accepts props for title, children, isActive, and onShow. It renders a section with heading, and conditionally shows children content if isActive is true, or a Show button that calls onShow if isActive is false.

Synced inputs lifting state pattern

To make two independent input components stay in sync, move the text state variable into the parent component along with the handleChange handler. Pass both value and onChange props to both Input components so they share the same state and stay synchronized.

Filtering a list with lifted state

To implement a searchable filtered list, lift the query state from SearchBar into the parent FilterableList component. Pass query and onChange props down to SearchBar as controlled props. In FilterableList, call the filter function with query to get filtered results and pass them to the List component.

Lifting state up definition

Lifting state up is the pattern of removing state from child components, moving it to their closest common parent component, and then passing it down via props. This is one of the most common things done when writing React code.

Regular variables don't persist between re-renders

Local variables declared with let or const inside a component function are recreated on every render. They cannot persist state between renders. To maintain values across re-renders, use state variables created with useState instead.

Don't use state for values only needed within a single event handler

State variables should only be used to persist information between re-renders. If a value is only needed within a single event handler function and doesn't need to persist, use a regular local variable instead.

Changing local variables doesn't trigger renders

Modifying a regular local variable will not cause React to re-render the component. React only re-renders when state variables are updated using their setter functions.

State requires two things to work

To update a component with new data, two things must happen: the data must be retained between renders, and React must be triggered to render the component again with new data. The useState Hook provides both: a state variable retains data between renders, and the setter function triggers a re-render.

State is local to component instance

State is specific to each instance of a component on the screen. When the same component is rendered multiple times, each instance has completely isolated state. Changing state in one instance does not affect the state of other instances.

State is private to the declaring component

State is fully private to the component that declares it. Parent components cannot access or change a child component's state, and child components cannot directly access parent state. Props are used to pass data downward.

Example: Using local variables instead of state for event handler values

export default function FeedbackForm() { function handleClick() { const name = prompt('What is your name?'); alert(`Hello, ${name}!`); } return ( <button onClick={handleClick}> Greet </button> ); } This example shows using a regular const variable instead of useState when the value is only needed within a single event handler.

Minimal state representation using DRY principle

State should be the minimal set of changing data that an app needs to remember. Apply the DRY (Don't Repeat Yourself) principle by figuring out the absolute minimal representation of state needed and computing everything else on-demand. For example, in a shopping list, store items as an array in state but compute the number of items by reading the array length rather than storing it as a separate state value.

Three criteria to identify what is state

Use three criteria to identify whether data should be state: Does it remain unchanged over time? If so, it is not state. Is it passed in from a parent via props? If so, it is not state. Can you compute it based on existing state or props in the component? If so, it definitely is not state. Everything that doesn't meet these criteria is state.

Props versus state distinction

Props and state are two types of model data in React with distinct purposes. Props are like arguments passed to a function - they let a parent component pass data to a child component to customize its appearance. State is like a component's memory - it lets a component keep track of information and change it in response to interactions. A parent component often keeps information in state and passes it down to child components as props.

Finding the common parent for state placement

To identify where state should live, follow these steps: identify every component that renders something based on that state; find their closest common parent component (a component above them all in the hierarchy); decide to put the state directly in the common parent, or in some component above the common parent, or create a new component solely for holding the state. The state should live in the component identified by this process.

Inverse data flow for updating parent state from child components

To support data flowing up the component hierarchy and allow child components to update parent state, pass callback functions down from the parent component to child components. The parent owns the state and passes the setter function (like setFilterText) to child components. Child components then call these callback functions with new values in response to user interactions, allowing child components to update the parent's state.

Interactive component example with state and event handlers

Here is a complete interactive version of the searchable product table with state and event handling: ```jsx import { useState } from 'react'; function FilterableProductTable({ products }) { const [filterText, setFilterText] = useState(''); const [inStockOnly, setInStockOnly] = useState(false); return ( <div> <SearchBar filterText={filterText} inStockOnly={inStockOnly} onFilterTextChange={setFilterText} onInStockOnlyChange={setInStockOnly} /> <ProductTable products={products} filterText={filterText} inStockOnly={inStockOnly} /> </div> ); } function ProductCategoryRow({ category }) { return ( <tr> <th colSpan="2"> {category} </th> </tr> ); } function ProductRow({ product }) { const name = product.stocked ? product.name : <span style={{ color: 'red' }}> {product.name} </span>; return ( <tr> <td>{name}</td> <td>{product.price}</td> </tr> ); } function ProductTable({ products, filterText, inStockOnly }) { const rows = []; let lastCategory = null; products.forEach((product) => { if ( product.name.toLowerCase().indexOf( filterText.toLowerCase() ) === -1 ) { return; } if (inStockOnly && !product.stocked) { return; } if (product.category !== lastCategory) { rows.push( <ProductCategoryRow category={product.category} key={product.category} /> ); } rows.push( <ProductRow product={product} key={product.name} /> ); lastCategory = product.category; }); return ( <table> <thead> <tr> <th>Name</th> <th>Price</th> </tr> </thead> <tbody>{rows}</tbody> </table> ); } function SearchBar({ filterText, inStockOnly, onFilterTextChange, onInStockOnlyChange }) { return ( <form> <input type="text" value={filterText} placeholder="Search..." onChange={(e) => onFilterTextChange(e.target.value)} /> <label> <input type="checkbox" checked={inStockOnly} onChange={(e) => onInStockOnlyChange(e.target.checked)} /> {' '} Only show products in stock </label> </form> ); } ``` This example demonstrates the complete React flow: managing state in the parent component, passing state and callbacks down through props, and handling user events to update parent state from child components.

History state stores all previous game states

The history state is an array of arrays, where each inner array represents a board state. For example: [[null,null,null,null,null,null,null,null,null], [null,null,null,null,'X',null,null,null,null]]. The last element is the current board state. This structure enables time travel features where you can jump back to any previous move.

Game component refactor - move state to top level

export default function Game() { const [xIsNext, setXIsNext] = useState(true); const [history, setHistory] = useState([Array(9).fill(null)]); const currentSquares = history[history.length - 1]; function handlePlay(nextSquares) { setHistory([...history, nextSquares]); setXIsNext(!xIsNext); } return ( <div className="game"> <div className="game-board"> <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} /> </div> <div className="game-info"> <ol>{/*TODO*/}</ol> </div> </div> ); } Moving state to the top-level Game component enables time travel by storing all historical board states.

tic-tac-toe example - Board component lifting state

function Board({ xIsNext, squares, onPlay }) { function handleClick(i) { if (calculateWinner(squares) || squares[i]) { return; } const nextSquares = squares.slice(); if (xIsNext) { nextSquares[i] = 'X'; } else { nextSquares[i] = 'O'; } onPlay(nextSquares); } const winner = calculateWinner(squares); let status; if (winner) { status = 'Winner: ' + winner; } else { status = 'Next player: ' + (xIsNext ? 'X' : 'O'); } return ( <> <div className="status">{status}</div> <div className="board-row"> <Square value={squares[0]} onSquareClick={() => handleClick(0)} /> <Square value={squares[1]} onSquareClick={() => handleClick(1)} /> <Square value={squares[2]} onSquareClick={() => handleClick(2)} /> </div> <div className="board-row"> <Square value={squares[3]} onSquareClick={() => handleClick(3)} /> <Square value={squares[4]} onSquareClick={() => handleClick(4)} /> <Square value={squares[5]} onSquareClick={() => handleClick(5)} /> </div> <div className="board-row"> <Square value={squares[6]} onSquareClick={() => handleClick(6)} /> <Square value={squares[7]} onSquareClick={() => handleClick(7)} /> <Square value={squares[8]} onSquareClick={() => handleClick(8)} /> </div> </> ); } The Board component receives state from its parent and handles click logic, delegating UI rendering to Square child components.

Lifting state up to parent component enables shared state

To share state between multiple child components or allow children to communicate, declare the shared state in their parent component. The parent can pass state down to children as props and provide callback functions for children to update that state. This keeps child components in sync with each other.

Calling setState triggers component re-render

When you call a state setter function (like setValue), React automatically re-renders that component and any child components that depend on that state. This update mechanism ensures the UI stays in sync with the state.

Each component instance has its own independent state

When multiple instances of a component exist, each maintains its own independent state. Changes to state in one component instance do not affect other instances of the same component.

Example: time travel with history slice and currentMove

function handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); } This example shows implementing time travel by slicing the history array up to currentMove before adding a new move. This ensures that if you go back in time and make a new move, only the history up to that point is kept.

Example: removing redundant xIsNext state variable

export default function Game() { const [history, setHistory] = useState([Array(9).fill(null)]); const [currentMove, setCurrentMove] = useState(0); const xIsNext = currentMove % 2 === 0; const currentSquares = history[currentMove]; function handlePlay(nextSquares) { const nextHistory = [...history.slice(0, currentMove + 1), nextSquares]; setHistory(nextHistory); setCurrentMove(nextHistory.length - 1); } function jumpTo(nextMove) { setCurrentMove(nextMove); } // ... } This example shows computing xIsNext from currentMove instead of storing it as state, eliminating the need for setXIsNext calls.

Benefit of avoiding redundant state

Avoiding redundant state reduces bugs and makes code easier to understand. There is no chance for derived values to get out of sync with their source state variables, even if you make a mistake while coding the components.

Computing derived state from other state

Instead of storing multiple state variables that depend on each other, you can derive one state value from another. For example, if xIsNext can always be computed from currentMove (xIsNext is true when currentMove is even), then xIsNext should be computed as a regular variable rather than stored as state: const xIsNext = currentMove % 2 === 0;

Fully controlled component receives all state as props

A fully controlled component has no internal state of its own. All state is passed in as props from a parent component, and all state updates go through callback functions passed as props. This pattern centralizes state management in the parent.

Reset state by passing key to component

To reset all state when a prop changes, split the component in two and pass the prop as a key attribute to the inner component. When the key changes, React treats it as a different component and recreates the DOM, resetting state of the component and all its children.

Controlled component pattern

A component that receives a value from its parent and calls a parent callback on changes is a controlled component. This makes the parent component manage the component's state, simplifying logic and making data flow predictable.

Lift state up instead of keeping synchronized

When trying to keep two state variables synchronized, lift state up to the parent component instead. This eliminates the need for synchronization logic and makes the data flow clearer.

Update parent state from child in event handler

When a child component needs to notify the parent of state changes, call the parent's callback function in the child's event handler, not in an Effect. This ensures the notification happens during the same interaction, not after render.

Give your agent this brain