In this article, I would like to show you the way of creating a reusable modal window in React.
But why is it worth doing? Because it makes the code more clean and transparent, helps to follow DRY convention and avoid making code too complicated. To implement this I used React, alt, reactstrap – as UI kit. Let’s start with the store – ModalStore.js
'use strict'; import alt from '../alt_instantiate'; import ModalActions from ‘../actions/modal_actions.jsx' class ModalStore { constructor() { this.bindListeners({ updateState: ModalActions.updateState, closeModal: ModalActions.closeModal }); this.visible = false; this.text = ''; this.headerText = ''; this.bodyText = ''; this.okButton = 'OK'; this.cancelButton = 'Отменить'; this.okAction = () => {}; this.cancelAction = () => { this.setState({visible: false})}; this.okColor = ‘danger'; } updateState(res) { this.visible = true; this.bodyText= res.bodyText; this.headerText = res.headerText; this.okButton = res.okButton || this.okButton; this.okAction = res.okAction || this.okAction; this.okColor = res.okColor || this.okColor; this.cancelAction = res.cancelAction || this.cancelAction; } closeModal(res) { this.visible = false } } module.exports = alt.createStore(ModalStore, ‘ModalStore');
We will use storage to store props of the modal window, like button names and types, title and content. ‘Visible’ property is responsible for the state of modal window(visible\hidden)
Next thing we need is action that keeps the store updated. It is how flux works. If you use redux – it’s called “reducer”
'use strict'; import alt from '../alt_instantiate'; class ModalActions { updateState(data) { return data; } closeModal() { return true } } module.exports = alt.createActions(ModalActions);
Component code:
import React from 'react'; import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; import ModalStore from '../../stores/modal_store.jsx' class ModalWindow extends React.Component { constructor(props) { super(props); this.state = { modal: false }; this.state = ModalStore.getState(); this.toggle = this.toggle.bind(this); this.onChange = this.onChange.bind(this) } componentDidMount() { ModalStore.listen(this.onChange) } componentWillUnmount() { ModalStore.unlisten(this.onChange) } onChange(res) { this.setState(res) } toggle() { this.setState({ modal: !this.state.modal }) } render() { return ( <div className="modal-component"> <Modal isOpen={this.state.visible} toggle={this.toggle} className={this.state.className}> <ModalHeader toggle={this.state.onCancel}>{this.state.headerText}</ModalHeader> <ModalBody> {this.state.bodyText} </ModalBody> <ModalFooter> <Button color={this.state.okColor} onClick={this.state.okAction}>{this.state.okButton}</Button>{' '} <Button color="secondary" onClick={this.state.cancelAction}>{this.state.cancelButton}</Button> </ModalFooter> </Modal> </div> ); } } export default ModalWindow;
The component has default functions and render(), which includes all UI that uses state from the ModalStore.jsx. The function componentDidMount() listening for the store changes and the react responds to it with re-render of that component. It goes automatically and we do not need to track the moment of the store updating, because of how react works.
Let’s see how we use modal window with other components. For example, we have a button that should open modal window.
//Skip boilerplate code render() { return( <div> <a className="dropdown-item" onClick={this.openModal}> Delete Post </a> </div> ) } openModal() { ModalActions.updateState(this.modalParams()); } modalParams() { return { bodyText: <div><div className={ this.state.classes } > <p>Do you really want to delete post</p> </div> </div> </div>, headerText: 'Delete post', okButton: 'Delete', okAction: this.onSubmitModal, okColor: 'info', cancelAction: this.closeModal }; };
As you may see from the code, we pass the object from the modalParams() to ModalAction, which contains our chosen properties. For each of the properties, we can use inline data, or component with its own logic, which can provide you 1 more abstraction layer for your logic.
Finally add modal component to your layout
Layout.isx
render() { return( <ModalWindow/> ..rest of your layout ) }
This is a very simple way to customize your component for any required case without duplicating the code and at the same time to keep control over the modal window.
In this example, I used modal window from bootstrap 4, but it can be replaced with any other.
Be Gera-Successful
Tags: javascript, modal window, react