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
useReducerhook.
🎯 Article Outline: What You'll Master
In this article, you will learn:
- ✅ The
useReducerHook: WhyuseReduceris a good choice for managing state with multiple actions. - ✅ Core Implementation: How to refactor the
useTogglehook to useuseReducer. - ✅ Practical Application: How to use the enhanced
useTogglehook 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 theuseReducerhook with our reducer and an initial value. It returns the current state (value) and adispatchfunction.dispatch({ type: '...' }): We create memoized functions (toggle,setTrue,setFalse) that call thedispatchfunction 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 ouruseTogglehook. We can renamesetTruetoopenModalandsetFalsetocloseModalfor better readability.<button onClick={openModal}>: We use theopenModalfunction to open the modal.<button onClick={closeModal}>: We use thecloseModalfunction 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:
useReduceris 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 touseStatefor 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.