useState Hook Cheatsheet

Basic Syntax

The useState hook is a fundamental concept in React for handling local component state. It helps you remember things like form values, counters, toggle states, etc., while the component is being rendered and re-rendered.

import { useState } from 'react';

function MyComponent() {
  const [state, setState] = useState(initialValue);
  // ...
}

Key Concepts

Common Patterns

Basic State Updates

// Direct update
setState(newValue);

// Update based on previous state
setState(prevState => prevState + 1);

Working with Object State

const [user, setUser] = useState({ name: '', email: '' });

// ❌ INCORRECT: Direct mutation
user.name = 'John';

// ✅ CORRECT
setUser({ ...user, name: 'John' });

Working with Array State

const [items, setItems] = useState([]);

// Add
setItems(prev => [...prev, newItem]);

// Remove
setItems(prev => prev.filter(item => item.id !== idToRemove));

// Update
setItems(prev => prev.map(item => item.id === idToUpdate ? { ...item, name: 'Updated' } : item));

Form Input State

const [inputValue, setInputValue] = useState('');

const handleChange = (e) => {
  setInputValue(e.target.value);
};

// In JSX
<input value={inputValue} onChange={handleChange} />

Multiple Input Form

const [formData, setFormData] = useState({
  firstName: '',
  lastName: '',
  email: ''
});

const handleChange = (e) => {
  const { name, value } = e.target;
  setFormData(prev => ({
    ...prev,
    [name]: value
  }));
};

// In JSX
<input name="firstName" value={formData.firstName} onChange={handleChange} />

Best Practices

Use Multiple State Variables for Unrelated Data

// ✅ GOOD
const [name, setName] = useState('');
const [age, setAge] = useState(0);

// ❌ NOT IDEAL
const [person, setPerson] = useState({ name: '', age: 0 });

Use a Single State Object for Related Data

const [formData, setFormData] = useState({
  username: '',
  password: '',
  email: ''
});

Use Callback Form When Updates Depend on Previous State

// ❌ RISKY
setCount(count + 1);

// ✅ SAFE
setCount(prevCount => prevCount + 1);

Avoid Redundant State

// ❌ BAD
const [firstName, setFirstName] = useState('John');
const [lastName, setLastName] = useState('Doe');
const [fullName, setFullName] = useState('John Doe');

// ✅ GOOD
const [firstName, setFirstName] = useState('John');
const [lastName, setLastName] = useState('Doe');
const fullName = `${firstName} ${lastName}`;

Initialization with Complex Values

// ❌ NOT IDEAL
const [data, setData] = useState(createExpensiveObject());

// ✅ GOOD
const [data, setData] = useState(() => createExpensiveObject());

Common Gotchas

State Updates are Asynchronous

setState(newValue);
console.log(state); // Still the old value!

useEffect(() => {
  console.log(state); // Now updated!
}, [state]);

State Updates Don't Merge Objects

// Class Component
this.setState({ name: 'John' });

// Functional Component
setUser({ name: 'John' }); // Removes other props!
setUser(prev => ({ ...prev, name: 'John' }));

State Updates Trigger Re-renders

Every time you call a state setter function, React re-renders the component unless the new state is the same as the previous one.

When to Use Other Hooks Instead