React Cheatsheet

State and useState

Use this React reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

useState — Basic Usage

import { useState } from 'react';

// Signature: const [state, setState] = useState(initialValue)
const [count, setCount] = useState(0);
const [name, setName] = useState('');
const [flag, setFlag] = useState(false);
const [items, setItems] = useState([]);
const [user, setUser] = useState(null);
const [data, setData] = useState({ x: 0, y: 0 });

Reading and Setting State

function Counter() {
  const [count, setCount] = useState(0);

  // Direct value update
  const reset = () => setCount(0);

  // Functional update — use when new state depends on previous state
  const increment = () => setCount(prev => prev + 1);
  const decrement = () => setCount(prev => prev - 1);
  const double    = () => setCount(prev => prev * 2);

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

Always use the functional form prev => ... when the new value depends on the old value. Direct setCount(count + 1) can use a stale value if called multiple times in one event.

Lazy Initial State

// If computing the initial value is expensive, pass a function — runs once only
const [data, setData] = useState(() => {
  return JSON.parse(localStorage.getItem('saved') ?? '[]');
});

Updating Objects

React state updates are shallow — always create a new object.

const [user, setUser] = useState({ name: 'Alice', age: 30, role: 'admin' });

// Spread the old object, override changed fields
const updateName = (name) => setUser(prev => ({ ...prev, name }));
const updateAge  = (age)  => setUser(prev => ({ ...prev, age }));

// Nested objects — must spread at every level
const [form, setForm] = useState({ address: { city: '', zip: '' } });
const updateCity = (city) =>
  setForm(prev => ({
    ...prev,
    address: { ...prev.address, city }
  }));

Updating Arrays

const [items, setItems] = useState([{ id: 1, text: 'Buy milk' }]);

// Add
const addItem = (item) => setItems(prev => [...prev, item]);
const prepend = (item) => setItems(prev => [item, ...prev]);

// Remove
const remove = (id) => setItems(prev => prev.filter(i => i.id !== id));

// Replace one item
const update = (id, changes) =>
  setItems(prev => prev.map(i => i.id === id ? { ...i, ...changes } : i));

// Sort (must copy first — sort() mutates)
const sortByName = () =>
  setItems(prev => [...prev].sort((a, b) => a.text.localeCompare(b.text)));

// Insert at index
const insertAt = (index, item) =>
  setItems(prev => [...prev.slice(0, index), item, ...prev.slice(index)]);

// Remove at index
const removeAt = (index) =>
  setItems(prev => prev.filter((_, i) => i !== index));

Multiple State Variables vs One Object

// Multiple — simpler, preferred when fields are unrelated
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');

// One object — useful when fields always update together
const [coords, setCoords] = useState({ x: 0, y: 0 });
const move = (x, y) => setCoords({ x, y }); // both always update together

State is Asynchronous / Batched

// setState does NOT immediately update the variable — reads are stale in the
// same synchronous block
function Example() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1); // schedules update
    console.log(count);  // still the OLD value — 0
  };

  // Fix: use functional form or read in the next render
  const handleClickFixed = () => {
    setCount(prev => {
      console.log(prev); // correct
      return prev + 1;
    });
  };
}

// React 18+ batches ALL setState calls (including in async/setTimeout/events)
// React 17 and below only batched inside React event handlers

Resetting State — Key Trick

Changing the key prop unmounts + remounts the component, resetting all its state.

function App() {
  const [userId, setUserId] = useState(1);

  // ProfileForm re-mounts fresh every time userId changes
  return <ProfileForm key={userId} userId={userId} />;
}

Derived State

Compute values from existing state rather than duplicating them.

// BAD — redundant state that can fall out of sync
const [items, setItems]   = useState([]);
const [total, setTotal]   = useState(0); // derived, don't store separately

// GOOD — compute during render
const [items, setItems] = useState([]);
const total = items.reduce((sum, i) => sum + i.price, 0); // derived

// If computation is expensive, memoize with useMemo
const sortedItems = useMemo(() => [...items].sort(...), [items]);

Lifting State Up

Move state to the closest common ancestor when two sibling components need to share it.

// Parent owns the shared state
function Parent() {
  const [value, setValue] = useState('');
  return (
    <>
      <Input value={value} onChange={setValue} />
      <Preview value={value} />
    </>
  );
}

function Input({ value, onChange }) {
  return <input value={value} onChange={e => onChange(e.target.value)} />;
}

function Preview({ value }) {
  return <p>Preview: {value}</p>;
}

Common Patterns and Gotchas

// Toggle boolean
const [open, setOpen] = useState(false);
const toggle = () => setOpen(prev => !prev);

// Increment / counter pattern
const [n, setN] = useState(0);
const inc = () => setN(n => n + 1);

// Track input value
const [text, setText] = useState('');
<input value={text} onChange={e => setText(e.target.value)} />

// GOTCHA: Objects/arrays must be NEW references for React to detect change
const [arr, setArr] = useState([1, 2, 3]);
arr.push(4);        // BAD — same reference, no re-render
setArr([...arr, 4]); // GOOD

// GOTCHA: State initialized from props is NOT automatically synced
function Child({ initialCount }) {
  const [count, setCount] = useState(initialCount); // ignores later prop changes
}
// Fix: either derive from props (no state) or use useEffect to sync (anti-pattern);
// better yet, lift state to parent.