# Introduction to React Hooks

> Learn how React Hooks let function components hold state with useState, run side effects with useEffect, and share logic through your own custom hooks.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2018-12-17 | Updated: 2026-07-18 | Topics: [React](https://flaviocopes.com/tags/react/) | Canonical: https://flaviocopes.com/react-hooks/

Hooks are functions that let React components use state and other React features.

They [became stable in React 16.8](https://legacy.reactjs.org/blog/2019/02/06/react-v16.8.0.html). Today they are the normal way to write stateful function components.

Hooks did not make class components invalid. Existing class components still work, and you can use classes and function components in the same application.

## Store state with useState

`useState()` adds a state variable to a component.

Pass its initial value. React returns the current state and a setter function:

```jsx
import { useState } from 'react'

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

  return (
    <button onClick={() => setCount(value => value + 1)}>
      Count is {count}
    </button>
  )
}
```

The array destructuring gives the two returned values useful names.

Calling `setCount()` asks React to render the component again with the new state. The updater function receives the previous value, which is useful when the next value depends on it.

You can call `useState()` more than once:

```jsx
const [name, setName] = useState('Flavio')
const [subscribed, setSubscribed] = useState(false)
```

Each call creates an independent piece of state.

Read the official [`useState` reference](https://react.dev/reference/react/useState) for initializers, updater functions, and common mistakes.

## Follow the Rules of Hooks

React depends on Hooks being called in the same order on every render.

Follow these two rules:

- call Hooks at the top level, not inside conditions, loops, or nested functions
- call Hooks only from React components or other Hooks

This is not valid:

```jsx
if (subscribed) {
  const [email, setEmail] = useState('')
}
```

Move the Hook to the top level and put the condition around the behavior that uses it.

The official [Rules of Hooks](https://react.dev/reference/rules/rules-of-hooks) explain why the call order matters. The React Hooks ESLint rules can catch these mistakes automatically.

## Synchronize with an external system using useEffect

`useEffect()` is for synchronizing a component with something outside React.

Examples include a browser event, timer, network connection, or third-party widget.

Do not think of an Effect as a direct replacement for `componentDidMount()` or another class lifecycle method. Think about the external process you need to start and stop.

For example, this component keeps a chat connection synchronized with `roomId`:

```jsx
import { useEffect } from 'react'
import { createConnection } from './chat.js'

export default function ChatRoom({ roomId }) {
  useEffect(() => {
    const connection = createConnection(roomId)
    connection.connect()

    return () => {
      connection.disconnect()
    }
  }, [roomId])

  return <h1>Room: {roomId}</h1>
}
```

The function returned by the Effect is its cleanup.

React runs the cleanup before synchronizing again with a changed `roomId`. It also runs the cleanup when the component is removed.

## Effect dependencies are not optional choices

The dependency array lists every reactive value read by the Effect.

In the previous example, the Effect reads `roomId`, so `[roomId]` is the correct dependency list.

If you leave out the dependency array, the Effect runs after every commit:

```jsx
useEffect(() => {
  logPageView()
})
```

An empty array means the Effect does not read changing values from the component:

```jsx
useEffect(() => {
  const id = setInterval(tick, 1000)
  return () => clearInterval(id)
}, [])
```

In development, Strict Mode runs an extra setup and cleanup cycle. This helps reveal Effects that do not clean up correctly.

Do not remove dependencies just to make an Effect run less often. Change the surrounding code so the Effect no longer reads that reactive value.

The official [`useEffect` reference](https://react.dev/reference/react/useEffect) documents the exact setup, cleanup, and dependency behavior.

Also remember this: if you are not synchronizing with an external system, you probably do not need an Effect.

## Share logic with a custom Hook

A custom Hook is a JavaScript function whose name starts with `use` and which calls other Hooks.

Here is a small `useToggle()` Hook:

```jsx
import { useState } from 'react'

export function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue)

  function toggle() {
    setValue(current => !current)
  }

  return [value, toggle]
}
```

Use it inside a component:

```jsx
import { useToggle } from './useToggle.js'

export default function Details() {
  const [open, toggle] = useToggle()

  return (
    <>
      <button onClick={toggle}>Toggle details</button>
      {open && <p>Here are the details.</p>}
    </>
  )
}
```

Custom Hooks share **stateful logic**, not the state itself. Two components that call `useToggle()` get two independent state values.

The official [custom Hooks guide](https://react.dev/learn/reusing-logic-with-custom-hooks) explains when extracting a Hook makes code clearer.

Not sure which hook fits your use case? Try my free [React hook chooser](https://flaviocopes.com/tools/react-hook-chooser/): describe what you want to do and it suggests the right hook, with a snippet.
