0

In my project, I want to be able to dispatch modal popups for things such as logging in and registering accounts. The problem I have is that I want them to be able to be used for any purpose, but I'm not sure about how to do it in the "React way". At first, I thought about doing it like this:

/constants/Modal.js

export const DISPATCH = 'MODAL/DISPATCH';
export const UPDATE = 'MODAL/UPDATE';
export const DISMISS = 'MODAL/DISMISS';

/actions/Modal.js

import {
    DISPATCH,
    UPDATE,
    DISMISS
} from '../constants/Modal';

export function dispatch(type, props) {
    return {
        type: DISPATCH,
        payload: {type, props}
    };
}

export function update(props) {
    return {
        type: UPDATE,
        payload: {props}
    };
}

export function dismiss() {
    return {type: DISMISS};
}

/reducers/Modal.js

import {Map} from 'immutable';

import {
    DISPATCH,
    UPDATE,
    DISMISS
} from '../constants/Modal';

const initialState = Map({
    type: '',
    props: Map(),
    isDispatched: false
});

export default function modalReducer(state = initialState, action) {
    switch (action.type) {
        case DISPATCH:
            return state.set('type', action.payload.type)
                .set('props', Map(action.payload.props))
                .set('isDispatched', true);
        case UPDATE:
            return state.set('props', Map(action.payload.props));
        case DISMISS:
            return state.set('isDispatched', false);
        default:
            return state;
    }
}

Components would then fire these actions, then the ModalContainer component would render the appropriate popup based on state.modal.get('type') and pass state.modal.get('props') to the Modal component. The issue with this is that props would end up including the component's children and various methods, which have no business being in the store. How can I render popups from components that aren't children of the ModalContainer component without doing something asinine like React.render(<Modal {...props}>, document.getElementById('modal-container'))?

kpimov
  • 13,632
  • 3
  • 12
  • 18

1 Answers1

2

I described a similar way of doing modal dialogues in this answer.
In my experience, I just don’t pass non-serializable props with the payload.

For example, rather than pass the children, I would encapsulate behavior in the appropriate modal component itself, e.g. <DeleteUserModal kind='sad' userId={42} hasErrors={false} />. It is then up to DeleteUserModal to connect to the store if necessary, retrieve the data it needs, dispatch the actions, and choose which children to render.

Alternatively you can avoid routing modals through Redux altogether and just use something like react-modal which actually does this for you:

doing something asinine like React.render(<Modal {...props}>, document.getElementById('modal-container'))?

(It’s not asinine, people call this pattern “a portal”.)

Community
  • 1
  • 1
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511