Creating Your First Custom Hook: `useToggle` (Part 2) - Adding More Features #83
📖 Introduction
Following our creation of a simple useToggle
hook, this article explores how we can make it even more powerful. We will add features to our useToggle
hook that allow us to set the value to true
or false
directly, in addition to toggling it.
📚 Prerequisites
Before we begin, please ensure you have a solid grasp of the following concepts:
- All concepts from Part 1 of this series.
- The
useReducer
hook.
🎯 Article Outline: What You'll Master
In this article, you will learn:
- ✅ The
useReducer
Hook: WhyuseReducer
is a good choice for managing state with multiple actions. - ✅ Core Implementation: How to refactor the
useToggle
hook to useuseReducer
. - ✅ Practical Application: How to use the enhanced
useToggle
hook in a component.
🧠 Section 1: The Core Concepts of useReducer
for useToggle
Our current useToggle
hook is great, but it only allows us to toggle the value. What if we want to explicitly set the value to true
or false
? We could add more functions to our hook, but a cleaner approach is to use the useReducer
hook.
useReducer
is an alternative to useState
. It is usually preferable to useState
when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.
For our useToggle
hook, we can use a reducer to handle three actions: TOGGLE
, SET_TRUE
, and SET_FALSE
.
💻 Section 2: Deep Dive - Implementation and Walkthrough
Let's refactor our useToggle
hook to use useReducer
.
2.1 - The useToggle
Hook with useReducer
// useToggle.js
import { useReducer, useCallback } from 'react';
const toggleReducer = (state, action) => {
switch (action.type) {
case 'TOGGLE':
return !state;
case 'SET_TRUE':
return true;
case 'SET_FALSE':
return false;
default:
return state;
}
};
function useToggle(initialValue = false) {
const [value, dispatch] = useReducer(toggleReducer, initialValue);
const toggle = useCallback(() => dispatch({ type: 'TOGGLE' }), []);
const setTrue = useCallback(() => dispatch({ type: 'SET_TRUE' }), []);
const setFalse = useCallback(() => dispatch({ type: 'SET_FALSE' }), []);
return [value, toggle, setTrue, setFalse];
}
export default useToggle;
Step-by-Step Code Breakdown:
toggleReducer
: We define a reducer function that takes the current state and an action, and returns the new state.useReducer(toggleReducer, initialValue)
: We use theuseReducer
hook with our reducer and an initial value. It returns the current state (value
) and adispatch
function.dispatch({ type: '...' })
: We create memoized functions (toggle
,setTrue
,setFalse
) that call thedispatch
function with the appropriate action type.return [value, toggle, setTrue, setFalse];
: We return the current value and our new functions.
🛠️ Section 3: Project-Based Example: A Modal Component
Now, let's use our enhanced useToggle
hook to manage a modal component.
// ModalComponent.js
import React from 'react';
import useToggle from './useToggle';
function ModalComponent() {
const [isOpen, toggle, openModal, closeModal] = useToggle(false);
return (
<div>
<button onClick={openModal}>Open Modal</button>
{isOpen && (
<div className="modal">
<div className="modal-content">
<p>This is a modal!</p>
<button onClick={closeModal}>Close</button>
</div>
</div>
)}
</div>
);
}
export default ModalComponent;
Code Breakdown:
const [isOpen, toggle, openModal, closeModal] = useToggle(false);
: We destructure the values from ouruseToggle
hook. We can renamesetTrue
toopenModal
andsetFalse
tocloseModal
for better readability.<button onClick={openModal}>
: We use theopenModal
function to open the modal.<button onClick={closeModal}>
: We use thecloseModal
function to close the modal.
💡 Conclusion & Key Takeaways
In this article, we've made our useToggle
hook even more powerful by using the useReducer
hook. We can now not only toggle the value, but also set it to true
or false
directly.
Let's summarize the key takeaways:
useReducer
is a great choice for managing state with multiple actions.- By using
useReducer
, we can make our custom hooks more flexible and powerful. - We can rename the functions returned from our custom hooks for better readability in our components.
Challenge Yourself:
To solidify your understanding, try to add a reset
action to the useToggle
hook that sets the value back to its initial state.
➡️ Next Steps
You now have a solid understanding of how to create a more advanced custom hook. In the next article, "A Custom Hook for Data Fetching: useFetch
(Part 1)", we will build a reusable hook for fetching data from an API.
Thank you for your dedication. Stay curious, and happy coding!
glossary
useReducer
: A React hook that is an alternative touseState
for managing state with complex logic.- Reducer: A pure function that takes the current state and an action, and returns the new state.
- Dispatch: A function that sends an action to a reducer.