43

Create a custom modal using React context, portals, and hooks

 5 years ago
source link: https://www.tuicool.com/articles/viaUJrb
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

n2aeAbY.png!web

This article will demonstrate how to construct and render a modal component that can be accessed from anywhere within your React application and populated with dynamic content. Before attempting a bespoke solution I would advise exploring any pre-existing modules that can provide you with a viable solution (e.g. Reach UI’s Dialog is an excellent, lightweight and highly accessible alternative). Otherwise, let’s dive in.

To better understand the problem, let’s start by creating a basic modal that conditionally renders depending on some local state. Clicking the button in the application root should trigger the modal, and clicking the button inside the modal should close it.

Example one: Basic modal implementation

This is only really useful if you need to trigger the modal from within <App/> , but what if you wanted the same functionality from a nested component? One option would be to pass the setState action setIsModalOpen as a prop and trigger the modal as a callback whenever a button within the nested component is clicked.

Example two: Triggering the modal via a callback prop

This works for a single level of nesting, but it probably won’t scale very well. What if we need to access the modal from heavily-nested components (10 / 100 / 1000 levels deep)? We could continue to pass our callback down through the components, but that quickly becomes laborious, difficult to maintain and creates a lot of excess code. Enter React Context .

In short, React’s Context API allows you to store a value in a Provider that can be accessed from anywhere in your application via a Consumer . Whenever a Consumer is declared, React will search up the component tree for the first Provider that matches the consumer’s context, return its value, and then subscribe to any further changes. Let’s wrap the previous example with a Provider, set the setIsModalOpen callback as its value, then utilise the useContext() hook to consume it in a nested component and bind it to a child button.

Example three: Triggering the modal via React context

Now we have a modal that can be triggered from anywhere in our application, but for the moment can only render static content. In order for the modal to render dynamically it will need refactored to handle children. React’s one-way data flow means that passing data upwards is considered an anti-pattern, so we’ll also need a viable way of passing the data from a nested component back up to the modal on the root.

Enter the coding powerhouse that isJenna Smith, an incredibly talented frontend developer and ex-colleague of mine. After discussing the problem with her she proposed React’s Portal as a solution, since they are explicitly designed to pass children to a DOM node that exists outside the hierarchy of the parent component. Creating a portal requires two arguments: any renderable React element (the dynamic content) and a DOM element to inject the content into (the modal).

Example four:Jenna Smith’s solution using React’s createPortal method

As you can see from her solution, she created two primary components to solve our earlier issues. The <ModalProvider /> component contains a DOM element with a ref attached ( <div ref={modalRef}/> ), and a context Provider that wraps the entire application and distributes the ref’s current value to any relevant Consumers within it. The second component is the modal itself. Whenever a <Modal/> component is rendered it will attempt to retrieve the modalRef element through useContext() . If a ref exists, instead of the component mounting in its expected position in the DOM tree it will instead create a React Portal and inject the modal’s children into the ref element. :boom:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK