React useReducer Hook

Introduction

useReducer() is used for state management in React components, providing a more predictable state transition by accepting a state and action in the reducer function.

Why use useReducer()?

useState() is usually the go-to Hook for state management in React. However, for complex state logic involving multiple sub-values or when the next state depends on the previous one, useReducer() might be a more suitable choice. It can also be beneficial when working with global state or when performance optimization is needed.

How it works

useReducer() is similar to Redux in terms of the concept of dispatching actions and reducing the state.

1
2
3
4
5
const [state, dispatch] = useReducer(reducer, initialArg, init);

// reducer: A function that takes the current state and an action, then returns a new state.  
// initialArg: The initial state.  
// init: An optional argument which allows you to lazily initialize the state.  

Reducer Function

The reducer function should be pure, which means it should return the same output for the same input, without any side effects.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function reducer(state, action) {
  switch (action.type) {
    case 'action description':
        // do something with state using action payload (if needed);
        const newState = {...state, action.payload.id}
        return newState;
    default:
      return state;
  }
}

Dispatching Actions

You can dispatch actions to update the state. It only receive one argument which is action. This means, when the dispatch() function is called, it will trigger the re-render if the reducer() function return a new state.
Whether it is a new state is checked using Object.is() function by React.

1
dispatch({type: 'action description', payload: 'any additional data'});

Example of use useReducer() and get action.payload from childComponent.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// countReducer function could be defined outside of the component for improving readability;
const countReducer = (state, action) => {
    swtich (action.type) {
        case "ADD": 
            return add(state, action.payload);
        case "SUB":
            return sub(state, action.payload);
    }
}  
// Define the parent component and set the state and dispatch;
const ParentComponent = () => {
    const [count, dispatchCount] = useReducer(countReducer, []);
    return (
        <div>
            <ChildComponent dispatch={dispatch} />
        </div>
    )
}
// define the child component;
const ChildComponent = (props) => {
    myRef = useRef();
    return (
        <div>
            <input type="text" ref={myRef}>
            <button onClick={() => handleClick("add")}> Increase </button>
            <button onClick={() => handleClick("sub")}> Decrease </button>
        </div>
    )
}

// define the click handler;

const handleClick = (type) => {
    const value = myRef.current.value;
    if (type ==== "add") {
        return props.dispatch({type: "ADD", payload: value})
    } else if (type === "sub") {
        return props.dispatch({type: "SUB", payload: value})
    }

}
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
© 2020 Lingyun Yang
Built with Hugo
Theme Stack designed by Jimmy