When to use useReducer over useState
useReducer
makes your state logic more declarative and flexible. Use it when you need to update multiple pieces of state at once. Use useState
for independent pieces of state.
More details
useState
and useReducer
are React Hooks that you can use to persist state between re-renders. Changing the state with both useState
and useReducer
will cause a re-render.
If you only need a single piece of state or multiple independent pieces of state, choose useState
to avoid the extra boilerplate work that comes with creating a reducer function and defining action types.
Use useReducer
when multiple pieces of the state need to be in sync. In other words, when a single effect, action or event causes multiple pieces of state to change at once, the useReducer
React Hook will make your code more declarative and flexible.
Let’s see this in action with useBeagles
, a custom React Hook that fetches photos of cute beagles from a public API. We’re going to create 2 versions of useBeagles
- one with useState
and another one with useReducer
. Then, we’ll compare the two.
The useBeagles
custom hook with useState
With useState
you have to imperatively change every single piece of state. Full example on Code Sandbox →
// ...
export default function useStateFetchApi(url) {
const [data, setData] = useState([])
const [error, setError] = useState(null)
const [loading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
fetch(url)
.then(res => {
setData(res.message)
setError(null)
setLoading(false)
})
.catch(err => {
setData([])
setError(err.message)
setLoading(false)
})
// ...
}, [url])
return { data, error, loading }
}
The useBeagles
custom hook with useReducer
With useReduce
, you describe what you want to change instead of how to change it. Full example on Code Sandbox →
// ...
function useBeagles(url) {
const [{ data, error, loading }, dispatch] = useReducer(reducer, initialState)
useEffect(() => {
dispatch({ type: FETCH_REQUEST })
fetch(url)
.then(res => {
dispatch({ type: FETCH_SUCCESS, payload: res.message })
})
.catch(err => {
dispatch({ type: FETCH_FAILURE, payload: err.message })
})
// ...
}, [url])
return { data, error, loading }
}
Thanks for reading! Have something to say? Please, leave a comment!