loading...

React Hooks - useState and useReducer cheat sheet - for developers who don't know Redux

mingyena profile image Rui Liu ・2 min read

I was having trouble to understand useReducer because I don't have Redux background. So I wrote this article to explain it to myself, and I hope it can help you as well.

Learn useState first

If you know how useState works, then you can skip this section, and I am going to compare useReducer to useState.

useState example (reactjs.org)


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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

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

  • useState(0): It passes the initial state (in this case, it is 0), and returns an array with 2 elements - count and setCount.
  • count: new state
  • setCount: the function that uses to change the state value. It is like this.setState() in class based component.

Compare to useReducer

useReducer is used for complicated state situation.
For example, I want to add one more button to decrease counter.

Here is the code by using useState

useState example (reactjs.org)

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

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

We are going to move count+1 and count -1 to a FUNCTION by using useReducer

const [count, setCount] = useReducer(FUNCTION, {count: 0})

In useReducer, we call count as state, setCount as dispatch, and FUNCTION is reducer

So it looks like this -

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

MDN explains pretty well what is Array.prototype.reduce() is. It may help you to understand what is the reducer funciton in useReducer.

Next, we are going to write the reducer function

reducer function passes 2 parameters

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();
  }
}

state: the current state
action: if I want to change state, then I call dispatch function. In this case, the first element is type, refer to action.type.

For example, I call dispatch({type: 'increment'}), then count will be + 1.

<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>

Full codes -

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, {count: 0});
  return (
      {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

Hope it will help you! ❤️

Posted on by:

mingyena profile

Rui Liu

@mingyena

I like to share ideas and snippets!

Discussion

pic
Editor guide
 

Wow, useReducer definitely looks cleaner than writing separate handlers for different state updates. Thanks for sharing :)