Toggle Boolean State Effectively in React
August 18, 2022Introduction
If we want to preserve some state in the React application, we are using an useState
hook. It is not bad, but is there any other option? Let's explore!
Let's create a custom hook that will return two values - the state and a function to update the state.
useState implementation
1import { useState } from 'react'23type UseToggleReturnType = {4 isToggled: boolean5 toggle: () => void6}78export const useToggle = (): UseToggleReturnType => {9 // We do not need to export the `setIsToggled` function, as we want to simplify the hook usage.10 const [isToggled, setIsToggled] = useState(false)1112 // Instead of providing the `setIsToggled` function, we have a specialized function to toggle the current state for us13 const toggle = () => {14 setIsToggled(!isToggled)15 }1617 return { isToggled, toggle }18}
Tests
As you may know, I'm a big fan of testing, so let's implement some tests!
1import { act, renderHook } from '@testing-library/react'23import { useToggle } from './use-toggle'45// assert that state and function to toggle the state are returned6describe('useToggle - return type', () => {7 const { result } = renderHook(() => {8 return useToggle()9 })1011 it('should return an object with a `isToggled` property, which is false', () => {12 expect(result.current).toHaveProperty('isToggled')13 expect(result.current.isToggled).toBe(false)14 })1516 it('should return an object with a `toggle` property, which is an function', () => {17 expect(result.current).toHaveProperty('toggle')18 expect(result.current.toggle).toBeInstanceOf(Function)19 })20})2122// verify if the state is updated when the toggle function is called23describe('useToggle - toggling', () => {24 it('should run the `toggle` function and check if `isToggled` is set to `true`', () => {25 const { result } = renderHook(() => {26 return useToggle()27 })2829 expect(result.current.isToggled).toBe(false)3031 act(() => {32 result.current.toggle()33 })3435 expect(result.current.isToggled).toBe(true)36 })37})
useReducer implementation
As we have tests already implemented, we can use the useReducer
hook to implement the same functionality.
Why useReducer
? Because it is a more powerful version of useState
, which allows us to use a reducer function to update the state based on the previous state.
1import { useReducer } from 'react'23type UseToggleReturnType = {4 isToggled: boolean5 toggle: () => void6}78export const useToggle = (): UseToggleReturnType => {9 // When calling a `toggle` function, a callback passed to the `useReducer` will be called with the previous state, returning the opposite state.10 const [isToggled, toggle] = useReducer((previousValue) => {11 return !previousValue12 // `false` is the initial state13 }, false)1415 return { isToggled, toggle }16}
Tests are still passing, and now we can use the useReducer
hook to implement the same, but with a more robust approach.
Conclusion
The aim of this article was not to show shorter code or to create some library but to show how to use the useReducer
hook instead of the useState
hook for managing the state that should be toggleable.
Have you found any bugs, or do you have any questions? Feel free to reach out on Twitter.
If you do not want to miss the next article, click on the follow button!