Irbisa · Cheatsheet

State & Events

useState, state as a snapshot, batching, updater functions, immutable updates of objects and arrays, lifting state up, events

Junior Developer · 20 questions

  1. 01

    What is state in React, and how does useState work?

    State is data a component remembers between renders and that changes over time.

    type User = { name: string }; function Counter() {  const [count, setCount] = useState(0);  const [user, setUser] = useState<User | null>(null);…
  2. 02

    Why does changing a regular local variable not update the screen, while useState does?

    A local variable is recreated on every render, and changing it tells React nothing, so no re-render happens and the next render starts from the initial value again.

  3. 03

    How do you handle events in React, and how do you pass an argument to a handler?

    You pass a function to a camelCase prop such as onClick or onChange, and React calls it with an event object when the event fires.

    type Item = { id: string; title: string }; function TodoList({ items, onRemove }: { items: Item[]; onRemove: (id: string) => void }) {  function handleSubmit(e: React.FormEvent<HTMLFormElement>) {    e.preventDefault(); // stop the full page reload    console.log('submitted');…
  4. 04

    Find the bug: this component crashes with "Too many re-renders" on its first render.

    function Greeting({ name }: { name: string }) {  const [upper, setUpper] = useState('');   setUpper(name.toUpperCase());   return <h1>{upper}</h1>;}

    The component calls setUpper during render: each call schedules another render, which calls it again, and React stops the loop with "Too many re-renders.

  5. 05

    Why must you update state immutably instead of changing an object or array in place?

    React decides whether to re-render by comparing the old and new state with Object.is, so a mutated object is still the same reference and the update can be skipped.

  6. 06

    How do you update an object, including a nested one, stored in state?

    Create a new object with spread syntax and the changed field, and pass it to the setter.

    type Person = { name: string; address: { city: string; zip: string } }; function Profile() {  const [person, setPerson] = useState<Person>({    name: 'Ada',    address: { city: 'London', zip: 'N1' },…
  7. 07

    Find the bug: typing in the search box resets the category filter to "All".

    type Filters = { query?: string; category?: string }; function ProductFilters() {  const [filters, setFilters] = useState<Filters>({ category: 'books' });   return (    <>      <input value={filters.query ?? ''} onChange={(e) => setFilters({ query: e.target.value })} />      <select value={filters.category ?? ''} onChange={(e) => setFilters({ category: e.target.value })}>        <option value="">All</option>        <option value="books">Books</option>      </select>    </>  );}

    The setter of useState replaces the state with exactly what you pass; it does not merge.

  8. 08

    How do you add, remove and update items in an array stored in state?

    Use methods that return a new array: spread to add, filter to remove, map to update, and pass the result to the setter.

    type Todo = { id: number; text: string; done: boolean }; function useTodos(initial: Todo[]) {  const [todos, setTodos] = useState(initial);   const add = (text: string) =>…
  9. 09

    What does "lifting state up" mean, and when do you do it?

    Lifting state up means moving state from two components into their closest common parent and passing it down as props, together with callbacks that change it.

    function Accordion() {  const [openIndex, setOpenIndex] = useState(0); // lifted from the panels   return (    <>      <Panel title="About" isOpen={openIndex === 0} onOpen={() => setOpenIndex(0)} />…
  10. 10

    What does "state is a snapshot" mean in React?

    Each render sees a fixed value of state for its whole lifetime: calling the setter does not change the variable you already have, it asks React to render again with the new value.

  11. 11

    What is the updater function form of a state setter, and when should you use it?

    Instead of a value you pass a function, setCount((c) => c + 1), and React calls it with the latest pending state while it processes the update queue.

    function Counter() {  const [count, setCount] = useState(0);   function addThree() {    setCount((c) => c + 1);    setCount((c) => c + 1);…
  12. 12

    What does the alert show and what does the button show after one click, and why?

    function Counter() {  const [number, setNumber] = useState(0);   function handleClick() {    setNumber(number + 5);    setNumber((n) => n + 1);    setNumber(number + 1);    alert(number);  }   return <button onClick={handleClick}>{number}</button>;}

    The alert shows 0 and the button then shows 1.

  13. 13

    What is batching in React, and what changed with automatic batching in React 18?

    Batching means React groups several state updates into one re-render instead of rendering after every setter call.

    import { flushSync } from 'react-dom'; function Chat() {  const [items, setItems] = useState<string[]>([]);  const [draft, setDraft] = useState('');  const listRef = useRef<HTMLUListElement>(null);…
  14. 14

    Find the bug: clicking "Add" does not show the new tag until you type in the input.

    function Tags() {  const [tags, setTags] = useState<string[]>(['react']);  const [text, setText] = useState('');   function handleAdd() {    tags.push(text);    setTags(tags);  }   return (    <>      <input value={text} onChange={(e) => setText(e.target.value)} />      <button onClick={handleAdd}>Add</button>      <p>{tags.join(', ')}</p>    </>  );}

    push mutates the existing array and setTags(tags) passes the same reference, so the Object.is check sees no change and React skips the re-render.

  15. 15

    What happens when you call a state setter with the value the state already has?

    React compares the new and the current value with Object.is, and if they are equal it skips re-rendering the component and its children.

  16. 16

    What is lazy initial state in useState, and when do you need it?

    If you pass a function, useState(() => compute()), React calls it only on the first render.

    function Notes() {  // JSON.parse runs only on the first render  const [notes, setNotes] = useState<string[]>(() => {    const saved = localStorage.getItem('notes');    return saved ? (JSON.parse(saved) as string[]) : [];  });…
  17. 17

    How do you structure component state well: what should and should not be stored in it?

    Keep the minimal state that cannot be computed: anything derivable from props or other state is calculated during render, not stored.

  18. 18

    How do preventDefault, stopPropagation and capture handlers work in React, and where does React attach its event listeners?

    React wraps native events in a SyntheticEvent, attaches one listener per event type to the root container and dispatches the event through your component tree.

    type CardProps = { onOpen: () => void; onShare: () => void }; function Card({ onOpen, onShare }: CardProps) {  return (    <div onClick={onOpen} onClickCapture={() => console.log('capture: runs first')}>      <a…
  19. 19

    How do you handle high-frequency events such as scroll, resize or pointermove without re-rendering on every event?

    Do not put every event into state.

    function ArticleHeader() {  const barRef = useRef<HTMLDivElement>(null);  const [scrolled, setScrolled] = useState(false);   useEffect(() => {    let frame = 0;…
  20. 20

    How would you implement undo and redo for a piece of React state?

    Keep a history instead of a single value: past, present and future in one useReducer.

    type History<T> = { past: T[]; present: T; future: T[] };type HistoryAction<T> = { type: 'set'; value: T } | { type: 'undo' } | { type: 'redo' }; const LIMIT = 100; // keep memory bounded function historyReducer<T>(state: History<T>, action: HistoryAction<T>): History<T> {…