DEV Community

Cover image for React Hooks Explained: useReducer and useMemo for Beginners
Vinayagam
Vinayagam

Posted on

React Hooks Explained: useReducer and useMemo for Beginners

Introduction

When I started learning React, I mostly used useState for everything. It worked well in the beginning, but as my project became a little bigger, managing state became confusing. I had multiple values, and sometimes one value depended on another. That is when I started learning about useReducer and useMemo.

In this blog, I will explain both in a simple way based on my understanding as a beginner.

useReducer

useReducer is a React Hook used to manage state in a more structured way. Instead of directly updating state like in useState, we use a separate function called a reducer. This function decides how the state should change.

The basic syntax looks like this:

const [state, dispatch] = useReducer(reducer, initialState);
Enter fullscreen mode Exit fullscreen mode

Here, state stores the current value, and dispatch is used to send an action. The reducer function takes the current state and the action, and returns a new state.

A simple reducer function looks like this:

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}
Enter fullscreen mode Exit fullscreen mode

When I first saw this, it looked confusing, but later I understood that the action simply tells what needs to be done. For example, if I want to increase the count, I can write:

dispatch({ type: "increment" });
Enter fullscreen mode Exit fullscreen mode

This will call the reducer and update the state.

Using it inside a component looks like this:

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

return (
  <div>
    <h2>{state.count}</h2>
    <button onClick={() => dispatch({ type: "increment" })}>+</button>
  </div>
);
Enter fullscreen mode Exit fullscreen mode

One thing I understood is that useReducer is very useful when state values are connected. For example, if I have count and total, and total depends on count, it is better to manage both together instead of using separate useState calls.

function reducer(state, action) {
  switch (action.type) {
    case "update":
      return {
        count: state.count + 1,
        total: state.total + state.count
      };
    default:
      return state;
  }
}
Enter fullscreen mode Exit fullscreen mode

This makes the logic easier to manage in one place.

useMemo

After learning useReducer, I faced another issue. My component was re-rendering again and again, and some calculations were running even when they were not needed. That is when I learned about useMemo.

useMemo is used to improve performance. It stores the result of a calculation and only recalculates it when required.

The syntax is simple:

const value = useMemo(() => {
  return calculation;
}, [dependencies]);
Enter fullscreen mode Exit fullscreen mode

At first, I did not understand what dependencies mean. Later I realized that dependencies are the values that control when the function should run again.

Here is a simple example:

const result = useMemo(() => {
  console.log("calculating");
  return count * 2;
}, [count]);
Enter fullscreen mode Exit fullscreen mode

In this example, the calculation runs only when count changes. If I update some other value like text input, this function will not run again.

const [count, setCount] = useState(0);
const [text, setText] = useState("");

const result = useMemo(() => count * 2, [count]);

return (
  <div>
    <h2>{result}</h2>
    <button onClick={() => setCount(count + 1)}>Increase</button>
    <input value={text} onChange={(e) => setText(e.target.value)} />
  </div>
);
Enter fullscreen mode Exit fullscreen mode

When I type in the input field, the component re-renders, but the calculation does not run again. This is how useMemo helps improve performance.

Top comments (0)