Explore custom useToggle hook use cases. Implement, type, and test it. Compare code before and after useToggle implementation for a clear understanding.
Let's understand why you may need the useToggle hook
Usually when creating components like: Dialogs, Menus, Modals, and Alerts, you need a flag that determines whether should something be displayed or not. With this flag, you need to provide 3 functions: open, close, and toggle. It will probably looks like the following code:
Imagine that you have tons of components like mentioned one and in addition in your application logic, you need to determine whether to show something or hide.
The next case may require assigning some data when you want to display UI parts - for example, you want to edit user data, so you need to store somewhere the current user object, update this object, close the form, and reset the object to initial value or just null.
This code is easy to understand but hard to maintain - the same repetitive logic, hard coded in different places. You need to write repeated tests to cover these cases for every component that needs to show/hide UI or for components that store some data during toggling.
This is the moment when lights turn on and we're kicking in with easy to use and type-safe hook. This hook will be called useToggle - it was really hard for me to find the appropriate name for this hook.
How we will use the useToggle hook?
We want to make this hook "flat" as possible to reduce the number of lines. So it will be used in the following way:
It's insane how we reduced the code from the previous example. Let's explore the full API of this hook:
Creating type definitions in TypeScript
Contracts in terms of type-safety are required to achieve protection from typos, invalid usage of functions, and invalid usage of returned data. Let's create them in separate file:
We've used generics T and we assigned the initial type to null. It means if we skip providing the generic type to hook, the default data type will be null.
Implementation process of the useToggle hook
Now it's time for implementation. With before-created type definitions, we'll be safe during implementation. Look at the following gif to understand the order and implementation process with defined contracts.
Ok, we know how it was implemented so let's explain each part of this implementation.
Now is the time for unit tests!
Unit tests for useToggle hook
We'll use the react-testing-library module that allows us to test hooks. We'll try to go through the typical use case of this hook and we'll check if the state changed correctly.
We started by assigning the initial state to our hook via configuration and then we closed, opened, toggled, and reassigned data. After each interaction, we checked the state.
Repository to play with implemented code. In addition below you have all the required code Copy and paste it and just use useToggle hook.
Look at type definitions file.
Now the implementation kicks in.
In the end the really important part - tests.
What did we learn in this lesson?
As you have probably seen, sometimes simple logic can be frustrating to work with if you need to repeat such logic in different places. This simple useToggle hook shows how you can wrap such logic inside a reusable, independent being.
What scenarios can be handled with this utility? It may be useful in creating any components like Modal, Menu, in simple words - to create something that appears and disappears.
In addition, we can assign additional data that may be useful when dealing with real business requirements or more complex components.
Everything is tested in a single place, so next time when you'll test your components you need to focus only on checking - is the useToggle hook used? If yes, you can skip testing these flags and data setup in your application/presentation-related components.
- 1. Rendering
Creating portals with custom usePortal hook
We will change the screens with useStepper hook
Manage components appearance with useToggle hook
Removing server warnings for useLayoutEffect with custom hook
First interaction detection with useOnInteraction hook
- 2. Forms
- 3. Events
Read the scroll metadata and direction with useScroll hook
Using clipboard with useClipboard hook
Detect outside click with the useClickOutside hook
Deep dive into useIntersectionObserver hook
Element size measurement with useElementSize hook
- 4. Guards
- 5. Interactions