We are implementing an application in React-Redux with stateless functional components and containers for the ones that need to handle state. The idea is to have all information in the Redux store.
In the application we need to show in several places different modal windows. I have looked into the articles here in stack overflow, but I cannot get this working. I have followed the process described by Dan Abramov in this post.
My main question is where I should render my ModalRoot component inside my application. The process is the following:
I have a button that dispatches an action displayModal in order to display a modal...
clickHandler: modalProps => ( dispatch(displayModal('MODAL_1', modalProps)) export function displayModal(modalType, modalProps) { return { type: DISPLAY_MODAL, payload: { modalType, modalProps } }; }
Then the action gets handled by a reducer that sets the modalType property in the redux-state...
export default function (modal = Map(), action) { if (!action) { return modal; } switch (action.type) { case DISPLAY_MODAL: return modal .set('modalType', action.payload.modalType) .set('modalProps', action.payload.modalProps); default: return modal; } }
Then I have the ModalRootContainer that passes the state to my ModalRoot component...
const mapStateToProps = state => ( { modalType: modalState(state).get('modalType'), modalProps: modalState(state).get('modalProps') } ); const ModalRootContainer = connect(mapStateToProps)(ModalRoot); export default ModalRootContainer;
ModalRootComponent is as follows:
const ModalRoot = (modalType, modalProps) => { if (!modalType) { return <span />; } switch (modalType) { case 'MODAL_1': return <MyComponent {...modalProps}/>; default: return <span />; } }; ModalRoot.propTypes = { modalType: PropTypes.string, modalProps: PropTypes.object }; export default ModalRoot;
My understanding is that this is correct but it does not work. Where should ModalRoot be placed? Inside the Provider tag? What am I missing?
Edit 1: I am trying to use what Random User is saying in his answer below with no effect. So I have in my index.html:
<body>
<div id="modals"></div>
<div id="root"></div>
</body>
In my main.js:
ReactDOM.render(
<Provider store={store}>
<Router history={hashHistory}>{routing(store)}</Router>
</Provider>,
document.getElementById('root')
);
ReactDOM.render(
<Provider store={store}>
<ModalRootContainer />
</Provider>,
document.getElementById('modals')
);
And with all the above setup still no modal is being shown. I debug and I see that the action is triggered and the state is updated from the reducer. Is there a way to debug after this point to see if something is wrong with my container and why is the modal not shown?
Edit 2: I have found what was wrong. I was passing wrongly the state to my container. The code seems to work, however now instead of having a modal window show, I am having my component (supposed to be inside the modal) appear above my remaining page. I am just rendering for the moment a simple text "Close modal" and a button to close it. It is shown and hidden correctly but it does not work as a modal, it just shows and hides. Any help on what I am missing?
ReactDOM.render( <ModalRootContainer />, document.getElementById('modals') );
While the entire app can render in a separate document node. This will allow you to style the model however you want and not affect the structure/ui of your<App />
. you can also use this for showing loading messages, alerts, this will act as an additional layer for different type of ui. – Dhruv Kumar JhaReactDOM.render( <Provider store={store}> <Router history={hashHistory}>{routing(store)}</Router> </Provider>, document.getElementById('root') );
– empyrealReactDOM.render
below that, You can callReactDOM.render
as many times as you want., UnlessModals
are integral part of you entire app, I would recommend you to use some existing libraries which provides Modals. You can place your additional code likeReactDOM.render( <Provider store={store}><ModalRootContainer /></Provider>, document.getElementById('modals') );
– Dhruv Kumar Jha