> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
> Use this file to discover all available pages before exploring further.

# Working with Hooks

> A comprehensive guide to using React Hooks in Preact

Hooks are a powerful feature in Preact that let you use state and other features without writing a class component. Preact's hooks implementation is fully compatible with React Hooks.

## What are Hooks?

Hooks are functions that let you "hook into" Preact state and lifecycle features from function components. They make it easier to reuse stateful logic between components and organize your code.

## Available Hooks

Preact provides all the standard hooks from the `preact/hooks` package:

* **useState** - Manage local state
* **useEffect** - Perform side effects
* **useReducer** - Alternative to useState for complex state
* **useRef** - Create a mutable ref object
* **useMemo** - Memoize expensive computations
* **useCallback** - Memoize callback functions
* **useContext** - Access context values
* **useLayoutEffect** - Run effects synchronously after DOM mutations
* **useImperativeHandle** - Customize ref exposure
* **useDebugValue** - Display custom hook labels in DevTools
* **useErrorBoundary** - Catch errors in components
* **useId** - Generate unique IDs for accessibility

## useState

The `useState` hook lets you add state to function components. It returns an array with the current state value and a function to update it.

<CodeGroup>
  ```jsx Counter Example theme={null}
  import { useState } from 'preact/hooks';

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

    return (
      <div>
        <p>Count: {count}</p>
        <button onClick={() => setCount(count + 1)}>
          Increment
        </button>
      </div>
    );
  }
  ```

  ```jsx Multiple State Variables theme={null}
  import { useState } from 'preact/hooks';

  function UserProfile() {
    const [name, setName] = useState('');
    const [age, setAge] = useState(0);
    const [email, setEmail] = useState('');

    return (
      <form>
        <input 
          value={name} 
          onChange={e => setName(e.target.value)} 
          placeholder="Name"
        />
        <input 
          type="number" 
          value={age} 
          onChange={e => setAge(e.target.value)}
          placeholder="Age"
        />
        <input 
          value={email} 
          onChange={e => setEmail(e.target.value)}
          placeholder="Email"
        />
      </form>
    );
  }
  ```
</CodeGroup>

### Functional Updates

When the new state depends on the previous state, pass a function to the setter:

```jsx theme={null}
function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    // Good: Uses functional update
    setCount(prevCount => prevCount + 1);
  };

  return <button onClick={increment}>Count: {count}</button>;
}
```

## useEffect

The `useEffect` hook lets you perform side effects in function components. Effects run **after** the browser paints, making them non-blocking.

<Steps>
  ### Basic Effect

  ```jsx theme={null}
  import { useState, useEffect } from 'preact/hooks';

  function Timer() {
    const [seconds, setSeconds] = useState(0);

    useEffect(() => {
      const interval = setInterval(() => {
        setSeconds(s => s + 1);
      }, 1000);

      // Cleanup function
      return () => clearInterval(interval);
    }, []); // Empty array = run once on mount

    return <div>Seconds: {seconds}</div>;
  }
  ```

  ### Effect Dependencies

  The second argument to `useEffect` is a dependency array. The effect re-runs when dependencies change:

  ```jsx theme={null}
  function UserData({ userId }) {
    const [user, setUser] = useState(null);

    useEffect(() => {
      fetch(`/api/users/${userId}`)
        .then(res => res.json())
        .then(setUser);
    }, [userId]); // Re-run when userId changes

    return user ? <div>{user.name}</div> : <div>Loading...</div>;
  }
  ```

  ### Cleanup

  Return a cleanup function from effects to clean up subscriptions, timers, etc:

  ```jsx theme={null}
  useEffect(() => {
    const subscription = api.subscribe(data => {
      console.log(data);
    });

    return () => {
      subscription.unsubscribe();
    };
  }, []);
  ```
</Steps>

## useReducer

For complex state logic, `useReducer` is often preferable to `useState`. It's built on top of `useState` internally.

```jsx theme={null}
import { useReducer } from 'preact/hooks';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    default:
      throw new Error('Unknown action type');
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>
        +
      </button>
      <button onClick={() => dispatch({ type: 'decrement' })}>
        -
      </button>
      <button onClick={() => dispatch({ type: 'reset' })}>
        Reset
      </button>
    </div>
  );
}
```

### Lazy Initialization

`useReducer` accepts an optional third argument for lazy initialization:

```jsx theme={null}
function init(initialCount) {
  return { count: initialCount };
}

function Counter({ initialCount }) {
  const [state, dispatch] = useReducer(
    reducer,
    initialCount,
    init  // Initialization function
  );
  
  // ...
}
```

## Rules of Hooks

Hooks have two important rules that must be followed:

<Tabs>
  <Tab title="Rule 1: Top Level Only">
    Only call hooks at the top level of your function. Don't call hooks inside loops, conditions, or nested functions.

    ```jsx theme={null}
    // Bad: Hook inside condition
    function Component({ condition }) {
      if (condition) {
        const [state, setState] = useState(0); // Don't do this!
      }
    }

    // Good: Hook at top level
    function Component({ condition }) {
      const [state, setState] = useState(0);
      
      if (condition) {
        // Use state here
      }
    }
    ```
  </Tab>

  <Tab title="Rule 2: Function Components Only">
    Only call hooks from Preact function components or custom hooks. Don't call them from regular JavaScript functions.

    ```jsx theme={null}
    // Bad: Hook in regular function
    function regularFunction() {
      const [state, setState] = useState(0); // Don't do this!
    }

    // Good: Hook in component
    function Component() {
      const [state, setState] = useState(0);
      return <div>{state}</div>;
    }

    // Good: Hook in custom hook
    function useCustomHook() {
      const [state, setState] = useState(0);
      return [state, setState];
    }
    ```
  </Tab>
</Tabs>

## Custom Hooks

Custom hooks let you extract component logic into reusable functions. They're just functions that use other hooks.

<CodeGroup>
  ```jsx useLocalStorage Hook theme={null}
  import { useState, useEffect } from 'preact/hooks';

  function useLocalStorage(key, initialValue) {
    // Get from local storage then parse stored json or return initialValue
    const [storedValue, setStoredValue] = useState(() => {
      try {
        const item = window.localStorage.getItem(key);
        return item ? JSON.parse(item) : initialValue;
      } catch (error) {
        console.log(error);
        return initialValue;
      }
    });

    // Return a wrapped version of useState's setter function that
    // persists the new value to localStorage.
    const setValue = value => {
      try {
        const valueToStore =
          value instanceof Function ? value(storedValue) : value;
        setStoredValue(valueToStore);
        window.localStorage.setItem(key, JSON.stringify(valueToStore));
      } catch (error) {
        console.log(error);
      }
    };

    return [storedValue, setValue];
  }

  // Usage
  function Component() {
    const [name, setName] = useLocalStorage('name', 'Bob');
    
    return (
      <input
        value={name}
        onChange={e => setName(e.target.value)}
      />
    );
  }
  ```

  ```jsx useFetch Hook theme={null}
  import { useState, useEffect } from 'preact/hooks';

  function useFetch(url) {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
      setLoading(true);
      fetch(url)
        .then(response => response.json())
        .then(data => {
          setData(data);
          setLoading(false);
        })
        .catch(error => {
          setError(error);
          setLoading(false);
        });
    }, [url]);

    return { data, loading, error };
  }

  // Usage
  function UserProfile({ userId }) {
    const { data, loading, error } = useFetch(`/api/users/${userId}`);

    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error: {error.message}</div>;
    return <div>{data.name}</div>;
  }
  ```

  ```jsx useDebounce Hook theme={null}
  import { useState, useEffect } from 'preact/hooks';

  function useDebounce(value, delay) {
    const [debouncedValue, setDebouncedValue] = useState(value);

    useEffect(() => {
      const handler = setTimeout(() => {
        setDebouncedValue(value);
      }, delay);

      return () => {
        clearTimeout(handler);
      };
    }, [value, delay]);

    return debouncedValue;
  }

  // Usage
  function SearchInput() {
    const [searchTerm, setSearchTerm] = useState('');
    const debouncedSearchTerm = useDebounce(searchTerm, 500);

    useEffect(() => {
      if (debouncedSearchTerm) {
        // API call with debounced value
        fetch(`/api/search?q=${debouncedSearchTerm}`)
          .then(res => res.json())
          .then(data => console.log(data));
      }
    }, [debouncedSearchTerm]);

    return (
      <input
        value={searchTerm}
        onChange={e => setSearchTerm(e.target.value)}
        placeholder="Search..."
      />
    );
  }
  ```
</CodeGroup>

## Best Practices

<Steps>
  ### Use descriptive state variable names

  Choose names that clearly indicate what the state represents:

  ```jsx theme={null}
  // Good
  const [isLoading, setIsLoading] = useState(false);
  const [userData, setUserData] = useState(null);

  // Less clear
  const [flag, setFlag] = useState(false);
  const [data, setData] = useState(null);
  ```

  ### Keep effects focused

  Each effect should handle one concern. Split complex effects into multiple smaller ones:

  ```jsx theme={null}
  // Good: Separate effects for separate concerns
  function Component({ userId }) {
    useEffect(() => {
      // Handle user data fetching
    }, [userId]);

    useEffect(() => {
      // Handle analytics tracking
    }, []);
  }

  // Less ideal: One effect doing too much
  function Component({ userId }) {
    useEffect(() => {
      // Fetching, tracking, and more...
    }, [userId]);
  }
  ```

  ### Extract reusable logic

  When you find yourself repeating the same hook patterns, extract them into custom hooks:

  ```jsx theme={null}
  // Before: Repeated pattern
  function ComponentA() {
    const [data, setData] = useState(null);
    useEffect(() => {
      fetch('/api/a').then(r => r.json()).then(setData);
    }, []);
  }

  function ComponentB() {
    const [data, setData] = useState(null);
    useEffect(() => {
      fetch('/api/b').then(r => r.json()).then(setData);
    }, []);
  }

  // After: Custom hook
  function useFetch(url) {
    const [data, setData] = useState(null);
    useEffect(() => {
      fetch(url).then(r => r.json()).then(setData);
    }, [url]);
    return data;
  }

  function ComponentA() {
    const data = useFetch('/api/a');
  }

  function ComponentB() {
    const data = useFetch('/api/b');
  }
  ```
</Steps>

## Implementation Details

Preact's hooks are implemented in `hooks/src/index.js` and integrate deeply with Preact's rendering system. Key implementation details:

* Hooks use an internal `currentComponent` variable to track which component is rendering
* Each hook call increments a `currentIndex` counter to maintain hook state between renders
* `useState` is implemented using `useReducer` internally
* Effects are queued and flushed after painting using `requestAnimationFrame`
* Hook state is stored in `component.__hooks._list` array

Reference: `hooks/src/index.js:172-175`

## Next Steps

<CardGroup cols={2}>
  <Card title="Context API" icon="share-nodes" href="/guides/context">
    Learn how to share state across components using Context
  </Card>

  <Card title="Refs" icon="link" href="/guides/refs">
    Access DOM elements and persist values with refs
  </Card>
</CardGroup>
