
Image by Kelly Sikkema from Unsplash
DESCRIPTION
Having too many dialogs, modals, popups in one component and state starts to become repetitive? Solution - write a custom hook for it.
Introduction
I'll use a bunch of Material UI components for preview example but
useToggles
hook works with any dialog/modal/popup component as it's just an encapsulated, reusable React state code.Preview
useToggles hook
x
import { useState } from "react";
export const useToggles = (initialToggles) => {
const [toggles, setToggles] = useState(initialToggles);
const handleToggles = (name, value) => {
setToggles({ ...toggles, [name]: value });
};
return {
toggles,
handleToggles
};
};
- First, we import the useState hook from React.
- Then, we create
useToggles
hook function which is acceptinginitialToggles
object as a parameter. initialToggles
could look like that:{ isDialogOneOpen: false, isDialogTwoOpen: true }
.- Then, we use the above object as a default value in the
useState
hook which returnstoggles
object andsetToggles
function to update them. handleToggles
function handler is updating the state of thetoggles
usingsetToggles
function, thename
parameter is a string name of the toggle to update, and thevalue
parameter is a boolean....
spread operator is used to clone existingtoggles
object and update a booleanvalue
of one concrete toggle by a stringname
parameter.- Lastly, we return
toggles
andhandleToggles
as an object from the hook function.
App - 2 dialogs
xxxxxxxxxx
import {
Dialog,
DialogTitle,
DialogActions,
Button,
Grid
} from "@material-ui/core";
import { useToggles } from "./useToggles";
import "./styles.css";
const ExampleDialog = ({ name, isOpen, onClose }) => (
<Dialog open={isOpen} onClose={onClose}>
<DialogTitle>{name}</DialogTitle>
<DialogActions>
<Button onClick={onClose} color="primary">
Close
</Button>
</DialogActions>
</Dialog>
);
export default function App() {
const { toggles, handleToggles } = useToggles({
isDialogOneOpen: false,
isDialogTwoOpen: false
});
return (
<div className="App">
<Grid justify="center" container spacing={1}>
<Grid item>
<Button
variant="outlined"
color="primary"
onClick={() => handleToggles("isDialogOneOpen", true)}
>
Open Dialog 1
</Button>
</Grid>
<Grid item>
<Button
variant="outlined"
color="primary"
onClick={() => handleToggles("isDialogTwoOpen", true)}
>
Open Dialog 2
</Button>
</Grid>
</Grid>
<ExampleDialog
name="Dialog 1"
isOpen={toggles.isDialogOneOpen}
onClose={() => handleToggles("isDialogOneOpen", false)}
/>
<ExampleDialog
name="Dialog 2"
isOpen={toggles.isDialogTwoOpen}
onClose={() => handleToggles("isDialogTwoOpen", false)}
/>
</div>
);
}
- Our app code looks a bit intimidating but mostly it's just a boilerplate code for rendering purposes. 😅
- First, we import all the necessary pieces.
- Then, we create
ExampleDialog
component to avoid duplication as we use 2 dialogs later on. - We use our sweet
useToggles
hook to control the state of our dialogs. toggles
andhandleToggles
are used in the above components to handle dialogs state.
Summary
- Extracting repetitive logic is a perfect use case for hooks in React.
- The above solution should work with any library and any dialog/modal/popup components as it's just a React state with extracted logic.
- To make it more scalable and include additional actions, e.g.
toggleAll
, useReducer hook would be a more appropriate solution thanuseState
. - The point of this pill is to grasp the ability to create custom hooks rather than presenting a concrete solution.