Manginag modals in react
Introduction
Websites use modals to enhance the user experience. Modals provide an effective way to present information and can be used to draw attention to key elements on a page. They can provide a user with a quick overview of a page’s content and can also be used to present options to the user. Modals can also be used to alert a user of an action or event that needs to be taken in order to complete a task. By using modals, websites can create a more interactive and engaging experience for their users.
Throughout this article, we will look at some of the ways that we can manage multiple modals within our application.
The typed approach
This approach is likely the most straightforward way to use modals, but it does require you to use Typescript in your codebase. We can employ a single state variable with a predefined type to control the modals on our page. The main benefits are that no unnecessary modals will be present, and we can easily identify which modals are active.
type MODALS = "CLOSED" | "CREATE_MODAL" | "EDIT_MODAL" | "DELETE_MODAL"
const [currentModal, setCurrentModal] = useState<MODALS>("CLOSED");
// in the render
currentModal === "CREATE_MODAL" && <CreateModal />
currentModal === "EDIT_MODAL" && <EditModal />
The modal factory approach
The factory approach uses a single component the registers all of the components in our application. This component will have to make use of the Redux store and will have to live at the top level of our application.
const ModalMap = {
modalName: ModalComponent,
modalName2: ModalComponent,
}
const ModalFactory = () => {
const activeModal = useSelector(getActiveModalName)
const modalProps = useSelector(getPropsToPass)
const Component = useMemo(() => {
if (activeModal) return ModalMap[activeModal];
return null;
}, [activeModal]);
if (!Component) return null;
return <Component {...modalProps}/>
}
In here we can see an example of registering all of our modals within an object, some other part of our application will dispatch the name of the modal that we want and this in turn will be rendered by the component that is looking for it. As modals tend to sit on top of our UI it doesn’t have to be tightly coupled to the component ingesting it.
The hook approach
In this example, we will create a hook which will enable us to register multiple Modals within each individual component. The only requirement is that we must return an array, as returning an Object would necessitate aliasing the open and close methods; however, an array allows us to circumvent this problem.
export const useModals = (modalName = '') => {
// add more modals here as we go on
const [state, setState] = useState({
[modalName]: false,
});
const openModal = () =>
setState({
...state,
[modalName]: true,
});
const closeModal = () =>
setState({
...state,
[modalName]: false,
});
return [
openModal,
closeModal,
[modalName]: state[modalName],
];
};
// in some component
// IF WE RETURN AN OBJECT
const { modalOne, openModal, closeModal } = useModals('modalOne');
// if using more than once we must alias the method names
// const { modalOne, openModal, closeModal } = useModals('modalOne'); will cause an error
const { modalTwo, openModal: openModalTwo, closeModal: closeModalTwo } = useModals('modalTwo');
// RETURNING AN ARRAY
const [openModalOne, closeModalOne, modalOneOpen] = useModals('modalOne')
const [openModalTwo, closeModalTwo, modalTwoOpen] = useModals('modalTwo')
Enhancing our hook with React Context
After posting this article I received some great feedback in comments around using Reacts context in order to manage modals. The following example makes use of React providers, context and hooks. I’d like to thank the people who took the time to comment on the article and help me understand this approach.
The provider in this case is quite simple, it’s going to store a similar state which will store a ReactElement which is our modal. We are then going to configure our openModal state to accept a modal name as the only parameter updating a piece of state in order to show us what to render.
The main advantage I can see with this approach is that it will ensure proper modal management across your application, it will also ensure that you cannot have duplicate modals. It will also provide you an easy means to search for specific modals for example in your ide you could search for registerModal(“name” and quickly find where it is used.
import { createContext, useContext, useState } from "react";
const ModalContextForHooks = createContext({});
export const useModals = () => useContext(ModalContextForHooks);
export const ModalContextForHooksProvider = ({ children }) => {
const [modalName, setModalName] = useState(null);
const [modals, setModals] = useState({});
const registerModal = (modalName, Component) => {
if (!modals[modalName]) {
setModals({
...modals,
[modalName]: Component
});
}
};
const openModal = (modalName) => {
setModalName(modalName);
};
const closeModal = () => {
setModalName("");
};
return (
<ModalContextForHooks.Provider
value={{ registerModal, openModal, closeModal }}
>
{modalName && modals[modalName]}
{children}
</ModalContextForHooks.Provider>
);
};
const ModalConsumer = () => {
const { registerModal, openModal, closeModal } = useModals();
registerModal("test", <ModalComponent />);
return (
<div>
<p>Click to open modal</p>
<button onClick={() => openModal("test")}>Click me</button>
<button onClick={closeModal}>Click me to close</button>
</div>
);
};
Conclusions
Modals can enhance the user experience by providing a streamlined, efficient way for users to interact with a website or application. Modals help keep users focused on the task at hand, as they don’t require users to navigate away from the current page to complete an action. Modals also offer a great way to display information to the user in a concise, easy-to-understand manner. By providing an intuitive, user-friendly way to perform common tasks, modals can ultimately create a better overall experience for users.
Above we have seen a few examples of how to achieve this technically and if anyone else would like to contribute other approaches in the comments it is always appreciated.