Using useState but forgetting to initialize it with a default value

Loading

Forgetting to Initialize useState with a Default Value

A common React mistake is declaring state with useState but forgetting to provide an initial value, which can lead to undefined errors and unexpected behavior.

The Problem

// ❌ Wrong - No initial value provided
const [count, setCount] = useState(); // count is undefined

// Later in component...
return <div>{count + 1}</div>; // NaN error

Why this is problematic:

  1. State variable starts as undefined
  2. Operations on undefined values cause errors (undefined + 1 = NaN)
  3. Can lead to runtime crashes
  4. Makes component behavior unpredictable

Correct Solutions

1. Basic Initialization

// ✅ Correct - Primitive value
const [count, setCount] = useState(0); // number
const [name, setName] = useState(''); // string
const [isActive, setIsActive] = useState(false); // boolean

2. Object Initialization

// ✅ Correct - Object state
const [user, setUser] = useState({
  name: '',
  email: '',
  age: null
});

3. Array Initialization

// ✅ Correct - Array state
const [items, setItems] = useState([]); // Empty array

4. Lazy Initialization (for expensive computations)

// ✅ Correct - Function initializer
const [data, setData] = useState(() => {
  const initialData = calculateExpensiveValue();
  return initialData;
});

Common Use Cases

Form Handling

function Form() {
  const [formData, setFormData] = useState({
    username: '',
    password: '',
    remember: false
  });

  // ...form handling logic
}

API Data Loading

function UserProfile() {
  const [user, setUser] = useState(null); // Explicit null for loading state
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    fetchUser().then(data => {
      setUser(data);
      setIsLoading(false);
    });
  }, []);

  if (isLoading) return <Spinner />;
  return <Profile user={user} />;
}

Best Practices

  1. Always initialize state – Even if just with null
  2. Match the expected type – Initialize with proper data structure
  3. Consider null states – For async data loading
  4. Document expected shape – With PropTypes or TypeScript
  5. Use descriptive defaults – That reveal the expected data structure

Common Mistakes to Avoid

  1. Partial initialization:
   const [user, setUser] = useState({}); // ❌ Missing properties
   console.log(user.name.first); // Error if nested
  1. Incorrect type defaults:
   const [count, setCount] = useState(''); // ❌ Expecting number
   setCount(count + 1); // String concatenation
  1. Forgetting async states:
   const [data, setData] = useState(); // ❌ No loading state
   return <div>{data.items.length}</div>; // Error when loading

Advanced Patterns

TypeScript Integration

interface User {
  id: number;
  name: string;
  email?: string;
}

function UserComponent() {
  const [user, setUser] = useState<User | null>(null);
  // ...type-safe operations
}

Reducer Alternative

// For complex state shapes
const [state, dispatch] = useReducer(reducer, {
  items: [],
  loading: false,
  error: null
});

  • What’s the expected data type?
  • What’s a sensible default value?
  • How should the component behave before data is loaded?

Leave a Reply

Your email address will not be published. Required fields are marked *