# useReducer, useMemo, and useCallback

React hooks provide an elegant way to manage state and lifecycle in functional components. Among these hooks, `useReducer`, `useMemo`, and `useCallback` offer powerful tools for handling complex state logic, optimizing performance, and managing dependencies. This blog dives deep into these hooks, explaining their usage with detailed examples.

### Table of Contents

1. **Introduction to Hooks**
2. **`useReducer` Hook**
   * Introduction
   * Basic Usage
   * Advanced Usage
   * Best Practices
3. **`useMemo` Hook**
   * Introduction
   * Basic Usage
   * Advanced Usage
   * Best Practices
4. **`useCallback` Hook**
   * Introduction
   * Basic Usage
   * Advanced Usage
   * Best Practices
5. **Combining Hooks**
6. **Conclusion**

### 1. Introduction to Hooks

React hooks were introduced in React 16.8, bringing state and lifecycle management to functional components. Among the various hooks, `useReducer`, `useMemo`, and `useCallback` are essential for managing complex state logic and optimizing performance.

### 2. `useReducer` Hook

#### Introduction

`useReducer` is a hook used for managing state in a React component, similar to `useState`. It is particularly useful for complex state logic where multiple sub-values or a state transition logic is involved. It also makes state management more predictable and easier to debug.

#### Basic Usage

The `useReducer` hook accepts a reducer function and an initial state, and returns an array containing the current state and a dispatch function. The reducer function takes the current state and an action, and returns the new state.

```jsx
import React, { useReducer } from 'react';

const initialState = { count: 0 };

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

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}

export default Counter;
```

#### Advanced Usage

`useReducer` shines with complex state logic. Let's consider a more advanced example: a form with multiple input fields.

```jsx
import React, { useReducer } from 'react';

const initialState = {
  username: '',
  email: '',
  password: ''
};

function reducer(state, action) {
  switch (action.type) {
    case 'setField':
      return {
        ...state,
        [action.field]: action.value
      };
    case 'reset':
      return initialState;
    default:
      throw new Error();
  }
}

function SignupForm() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const handleChange = (e) => {
    dispatch({ type: 'setField', field: e.target.name, value: e.target.value });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(state);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        name="username"
        value={state.username}
        onChange={handleChange}
        placeholder="Username"
      />
      <input
        type="email"
        name="email"
        value={state.email}
        onChange={handleChange}
        placeholder="Email"
      />
      <input
        type="password"
        name="password"
        value={state.password}
        onChange={handleChange}
        placeholder="Password"
      />
      <button type="submit">Submit</button>
      <button type="button" onClick={() => dispatch({ type: 'reset' })}>
        Reset
      </button>
    </form>
  );
}

export default SignupForm;
```

#### Best Practices

* **Keep the reducer function pure**: The reducer function should not have side effects. It should only compute and return the new state.
* **Use action types and payloads**: Define action types as constants to avoid typos and make the code more readable.
* **Consider performance**: For performance-critical applications, consider using `useMemo` and `useCallback` to prevent unnecessary re-renders.

### 3. `useMemo` Hook

#### Introduction

`useMemo` is a hook used to memoize the result of a computation. It returns a memoized value, and recomputes it only when one of its dependencies changes. This can optimize performance by preventing expensive calculations on every render.

#### Basic Usage

```jsx
import React, { useState, useMemo } from 'react';

function ExpensiveComponent({ count }) {
  const expensiveCalculation = (num) => {
    console.log('Calculating...');
    for (let i = 0; i < 1000000000; i++) {} // simulate expensive calculation
    return num * 2;
  };

  const memoizedValue = useMemo(() => expensiveCalculation(count), [count]);

  return <div>Calculated Value: {memoizedValue}</div>;
}

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

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ExpensiveComponent count={count} />
    </div>
  );
}

export default App;
```

#### Advanced Usage

In more complex scenarios, you might have multiple dependencies and need to ensure that the memoized value is recalculated only when necessary.

```jsx
import React, { useState, useMemo } from 'react';

function ProductList({ products }) {
  const sortedProducts = useMemo(() => {
    console.log('Sorting products...');
    return [...products].sort((a, b) => a.name.localeCompare(b.name));
  }, [products]);

  return (
    <ul>
      {sortedProducts.map((product) => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

function App() {
  const [products, setProducts] = useState([
    { id: 1, name: 'Apple' },
    { id: 2, name: 'Orange' },
    { id: 3, name: 'Banana' },
  ]);

  const addProduct = () => {
    setProducts([...products, { id: products.length + 1, name: 'Mango' }]);
  };

  return (
    <div>
      <button onClick={addProduct}>Add Product</button>
      <ProductList products={products} />
    </div>
  );
}

export default App;
```

#### Best Practices

* **Use only when necessary**: `useMemo` should be used for expensive calculations that could cause performance issues if re-computed on every render.
* **Manage dependencies correctly**: Ensure all dependencies that affect the memoized value are included in the dependency array.
* **Combine with `useCallback`**: Often used together with `useCallback` to optimize both values and functions.

### 4. `useCallback` Hook

#### Introduction

`useCallback` is a hook used to memoize a function. It returns a memoized version of the callback that only changes if one of its dependencies changes. This can prevent unnecessary re-renders, particularly when passing callbacks to child components.

#### Basic Usage

```jsx
import React, { useState, useCallback } from 'react';

function Child({ onClick }) {
  console.log('Child render');
  return <button onClick={onClick}>Click me</button>;
}

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

  const increment = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <Child onClick={increment} />
    </div>
  );
}

export default App;
```

#### Advanced Usage

For more advanced usage, consider a scenario where you need to handle multiple callbacks with different dependencies.

```jsx
import React, { useState, useCallback } from 'react';

function List({ items, onItemClick }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index} onClick={() => onItemClick(item)}>
          {item}
        </li>
      ))}
    </ul>
  );
}

function App() {
  const [items] = useState(['Apple', 'Orange', 'Banana']);
  const [selectedItem, setSelectedItem] = useState(null);

  const handleItemClick = useCallback((item) => {
    setSelectedItem(item);
  }, []);

  return (
    <div>
      <List items={items} onItemClick={handleItemClick} />
      {selectedItem && <p>Selected Item: {selectedItem}</p>}
    </div>
  );
}

export default App;
```

#### Best Practices

* **Use for stable references**: Use `useCallback` when passing callbacks to optimized child components that rely on reference equality to avoid unnecessary renders.
* **Manage dependencies correctly**: Ensure all dependencies that affect the callback are included in the dependency array.
* **useMemo**: Often used together with `useMemo` to optimize both values and functions.

### 5. Combining Hooks

Combining `useReducer`, `useMemo`, and `useCallback` can lead to highly optimized and maintainable code, especially in complex applications.

#### Example: Todo List Application

Let's build a Todo List application that demonstrates the combined usage of `useReducer`, `useMemo`, and `useCallback`.

```jsx
import React, { useReducer, useMemo, useCallback } from 'react';

// Initial State
const initialState = {
  todos: [],
  filter: 'all',
};

// Reducer Function
function reducer(state, action) {
  switch (action.type) {
    case 'addTodo':
      return { ...state, todos: [...state.todos, action.todo] };
    case 'toggleTodo':
      return {
        ...state,
        todos: state.todos.map((todo, index) =>
          index === action.index ? { ...todo, completed: !todo.completed } : todo
        ),
      };
    case 'setFilter':
      return { ...state, filter: action.filter };
    default:
      throw new Error();
  }
}

function TodoApp() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const filteredTodos = useMemo(() => {
    switch (state.filter) {
      case 'completed':
        return state.todos.filter((todo) => todo.completed);
      case 'active':
        return state.todos.filter((todo) => !todo.completed);
      default:
        return state.todos;
    }
  }, [state.todos, state.filter]);

  const addTodo = useCallback((text) => {
    dispatch({ type: 'addTodo', todo: { text, completed: false } });
  }, []);

  const toggleTodo = useCallback((index) => {
    dispatch({ type: 'toggleTodo', index });
  }, []);

  const setFilter = useCallback((filter) => {
    dispatch({ type: 'setFilter', filter });
  }, []);

  return (
    <div>
      <TodoList todos={filteredTodos} onToggle={toggleTodo} />
      <AddTodoForm onAddTodo={addTodo} />
      <FilterButtons filter={state.filter} onSetFilter={setFilter} />
    </div>
  );
}

function TodoList({ todos, onToggle }) {
  return (
    <ul>
      {todos.map((todo, index) => (
        <li key={index} onClick={() => onToggle(index)}>
          {todo.text} {todo.completed ? '(Completed)' : ''}
        </li>
      ))}
    </ul>
  );
}

function AddTodoForm({ onAddTodo }) {
  const [text, setText] = React.useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    onAddTodo(text);
    setText('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Add a new todo"
      />
      <button type="submit">Add</button>
    </form>
  );
}

function FilterButtons({ filter, onSetFilter }) {
  return (
    <div>
      <button disabled={filter === 'all'} onClick={() => onSetFilter('all')}>
        All
      </button>
      <button disabled={filter === 'active'} onClick={() => onSetFilter('active')}>
        Active
      </button>
      <button disabled={filter === 'completed'} onClick={() => onSetFilter('completed')}>
        Completed
      </button>
    </div>
  );
}

export default TodoApp;
```

In this example:

* **State Management**: `useReducer` manages the state of todos and the current filter.
* **Performance Optimization**: `useMemo` memoizes the filtered todos list to avoid unnecessary recalculations.
* **Callback Optimization**: `useCallback` memoizes the functions to prevent unnecessary re-renders of child components.

### 6. Conclusion

Understanding and effectively using `useReducer`, `useMemo`, and `useCallback` can significantly enhance your ability to manage complex state logic and optimize performance in React applications. These hooks provide powerful tools for creating more efficient, maintainable, and predictable React components.

* **`useReducer`**: Ideal for managing complex state logic with multiple actions and state transitions.
* **`useMemo`**: Useful for memoizing expensive calculations to prevent unnecessary re-renders.
* **`useCallback`**: Helps in memoizing functions to maintain stable references, avoiding unnecessary re-renders of child components.

By combining these hooks, you can build sophisticated and performant React applications.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://guvi.gitbook.io/fsd/docs/module-5-reactjs/deep-down-with-react-hooks/usereducer-usememo-and-usecallback.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
