Pure React Modal

Let’s start by setting initial state of the component: state = { fadeType: null }; and when the component mounts, we’ll set the state to in so that the className we declared of StyledModal can be used:componentDidMount() { setTimeout(() => this.

setState({ fadeType: "in" }), 0);}Why can’t we just set initial State to true?Because with the lifecycle of a React Component, the initial render will include the className in and in this case, by the time the component is actually mounted, there is no “transition” change.

There is probably a workaround to this, but it seems easier to read and understand the functionality this way, IMO.

Now, when the modal opens, the CSS properties activate for transition and React handles it like any other event, such as onClick.

Cool!We initially declared onTransitionEnd which references the callback function transitionEnd so in our Modal class let’s add this method.

// Modal.

jstransitionEnd = e => { if (e.

propertyName !== "opacity" || this.

state.

fadeType === "in") return; if (this.

state.

fadeType === "out") { this.

props.

onClose(); }};There’s nothing we need to do on a fade in, but on fade out we do want to trigger the onClose prop method so the Parent state is updated.

Let’s consider Acceptance Criteria #2 and #3 handled.

Now to handle an Escape key to close, this should be fairly straight forward.

In the ComponentDidMount let’s add an eventListener and corresponding callback function:// Modal.

jscomponentDidMount() { window.

addEventListener("keydown", this.

onEscKeyDown, false); setTimeout(() => this.

setState({ fadeType: "in" }), 0);}onEscKeyDown = e => { if (e.

key !== "Escape") return; this.

setState({ fadeType: "out" });};Now our state is updated and the transition event kicks in again.

Let’s consider the Acceptance Criteria #4 complete.

The same logic applies to a modal “close” button:// Modal.

jshandleClick = e => { e.

preventDefault(); this.

setState({ fadeType: "out" });};And now, we have a working modal that covers content, fades in and fades out, and has an escape key close function:Live example of Pure React modalHere’s the full Modal component code:import React, { Component } from "react";import ReactDom from "react-dom";import PropTypes from "prop-types";// styledimport StyledModal from ".

/Modal.

css";const modalRoot = document.

getElementById("modal-root");class Modal extends Component { static defaultProps = { id: "", modalClass: "", modalSize: "md" };static propTypes = { id: PropTypes.

string.

isRequired, onClose: PropTypes.

func.

isRequired, isOpen: PropTypes.

bool.

isRequired, modalClass: PropTypes.

string, modalSize: PropTypes.

string };state = { fadeType: null };background = React.

createRef();componentDidMount() { window.

addEventListener("keydown", this.

onEscKeyDown, false); setTimeout(() => this.

setState({ fadeType: "in" }), 0); }componentDidUpdate(prevProps, prevState) { if (!this.

props.

isOpen && prevProps.

isOpen) { this.

setState({ fadeType: "out" }); } }componentWillUnmount() { window.

removeEventListener("keydown", this.

onEscKeyDown, false); }transitionEnd = e => { if (e.

propertyName !== "opacity" || this.

state.

fadeType === "in") return;if (this.

state.

fadeType === "out") { this.

props.

onClose(); } };onEscKeyDown = e => { if (e.

key !== "Escape") return; this.

setState({ fadeType: "out" }); };handleClick = e => { e.

preventDefault(); this.

setState({ fadeType: "out" }); };render() { return ReactDom.

createPortal( <StyledModal id={this.

props.

id} className={`wrapper ${"size-" + this.

props.

modalSize} fade-${ this.

state.

fadeType } ${this.

props.

modalClass}`} role="dialog" modalSize={this.

props.

modalSize} onTransitionEnd={this.

transitionEnd} > <div className="box-dialog"> <div className="box-header"> <h4 className="box-title">Title Of Modal</h4> <button onClick={this.

handleClick} className="close"> × </button> </div> <div className="box-content">{this.

props.

children}</div> <div className="box-footer"> <button onClick={this.

handleClick} className="close"> Close </button> </div> </div> <div className={`background`} onMouseDown={this.

handleClick} ref={this.

background} /> </StyledModal>, modalRoot ); }}export default Modal;And a big kudos to my super talented co-worker, Senior JavaScript Engineer Abhishek Saha, for providing me with so much knowledge over the last year-plus.

Your skills and knowledge about JS & React always impress.

.

. More details

Leave a Reply