Skip to content

Instantly share code, notes, and snippets.

@kettanaito
Last active April 8, 2023 11:13
Show Gist options
  • Save kettanaito/2ba1873c6fa0adf75e121eb2de92a7cb to your computer and use it in GitHub Desktop.
Save kettanaito/2ba1873c6fa0adf75e121eb2de92a7cb to your computer and use it in GitHub Desktop.
A draft for "withModal" HOC to allow easy modals in React.
export const SHOW_MODAL = 'SHOW_MODAL';
export const showModal(modalId, modalParams) => ({
type: SHOW_MODAL,
modalId,
modalParams
});
/* App.jsx */
import React from 'react';
import EmailChange from './EmailChange';
import ConfirmationModal from './ConfirmationModal';
export default class App extends React.Component {
render() {
return (
<EmailChange />
<ConfirmationModal />
);
}
}
/* ConfirmationModal.jsx */
import React from 'react';
import PropTypes from 'prop-types';
import withModal from './withModal';
class ConfirmationModal extends React.Component {
static propTypes = {
id: PropTypes.string.isReqiured
}
static defaultProps = {
id: 'confirmation'
}
handleConfirmClick = () => {
this.props.hideModal('confirmation'); // you may want to generate the action relevant to this id and pass it from HOC
}
render() {
const { modalParams } = this.props;
return (
<div className="modal">
<h1>Hey!</h1>
<p>Are you sure you want a "{ modalParams.email }" as your new email?</p>
<button onClick={ this.handleConfirmClick }>Confirm</button>
</div>
);
}
}
export default withModal(ConfirmationModal);
/* EmailChange.jsx */
import React from 'react';
import { connect } from 'react-redux';
class EmailChange extends React.Component {
render() {
return (
<div>
<button onClick={() => {
this.props.showModal('confirmation', { email: 'foo@reactjs.com' });
}}>
Change email
</button>
</div>
);
}
}
export default connect(undefined, { showModal })(EmailChange);
import * as actions from './actions';
const initialState = {
ids: [],
params: {}
};
export default function modalReducer(state, action) {
switch (action.type) {
case actions.SHOW_MODAL:
const { modalId, modalParams } = action;
const nextState = Object.assign({}, state, { modalParams });
if (state.modals.includes(modalId)) {
nextState.ids.splice(state.ids.indexOf(modalId), 1);
} else {
nextState.ids = state.ids.concat(modalId);
}
return nextState;
}
}
/* withModal.jsx */
import React from 'react';
import { connect } from 'react-redux';
import { showModal, hideModal } from './actions';
export default function withModal(CustomModal) {
class ModalWrapper extends React.Component {
render() {
const { id, modals } = this.props;
if (!modals.ids.ncludes(id)) return null;
return React.createElement(CustomModal, this.props);
}
}
return connect(state => ({
modals: state.modals,
modalParams: state.modals.params
}), { showModal, hideModal })(ModalWrapper);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment