Scalable Modals with React and Redux

I have tried many ways for setting up a scalable way to create modals with React and Redux. The approach that I ended up using is basically a tweaked version from a Stackoverflow answer from Dan Abramov’s 

Modals

Creating modals in React is pretty simple, many solutions implement React Portals but I think rendering a Modal outside of the application container is overkill, we use a ModalRoot container which we render in our application container instead.

So I talk here about a solution that is scalable, testable and simple. It requires some boilerplate code to setup but it’s worth it in the long run.

Repository

Here is a repository with the solution, keep reading if you want a detailed explanation.

Github repository

Creating a view Modal component

First we setup a very basic Modal component, which we are going to use to implement different kinds of Modals such as Notification, Confirmation etc.

To keep things as simple as possible, I don’t use any css files, but I use styled-components. It’s a very nice library to add styling to your components, and I highly recommend you check it out, but feel free to translate the components styling to your project (scss, less etc.)

[gistpen id=”45″]

Setting up the Redux magic

To create all the Redux logic and set this up correctly we are going to add/change:

  • actions/modal.js (new)
  • reducers/modal.js (new)
  • constants/ModalTypes.js (new)
  • constants/ActionTypes.js (changed)

First we have to add 2 new action types SHOW_MODAL and HIDE_MODAL to your project.

[gistpen id=”49″]

Next we are going to add 2 new action dispatchers showModal and hideModal

[gistpen id=”47″]

Now lets create a reducer to handle our actions.

NOTE: Don’t forget to include the reducer to your root reducer!

[gistpen id=”51″]

Next is creating a new file in your constants ModalTypes, more info on this later.

[gistpen id=”53″]

Creating a Notification modal type

As you can see above, in the ModalTypes file we added Notification and Confirmation as modal types, lets first create a Notification modal.

The notification modal type is just to show a popup message with a button to close it (ok).

[gistpen id=”55″]

Creating a Confirmation modal type

Another modal type we are going to add is a confirmation, which is slightly different than our notification modal type, because it asks the user to confirm (yes / no).

[gistpen id=”59″]

Creating a ModalRoot container

The ModalRoot container which we are going to create is responsible for rendering the correct modal component in your RootContainer with its correct properties.

[gistpen id=”57″]

Adding the ModalRoot container to your RootContainer

The final step is to add your ModalRoot container to your RootContainer, depending on your project, this is mostly called App or Root.

So add the ModalRoot to your App container, in our example repository it looks like this:

[gistpen id=”61″]

How to use it?

So now everything is setup, but how do you use it? It’s pretty simple. Lets create an demo LoginView where we show 2 buttons:

  • Show modal: Clicking this button shows a notification modal
  • Show confirm: Clicking this button shows a confirmation modal, and when confirmed it shows a notification modal with the result (whether the user confirmed or not)

What we have to do is pretty simple:

  • We connect our View and inject the showModal action
  • We include the Modal type constant from which modals we want to show, in this case we want to show a notification and confirmation modal, so we include: MODAL_TYPE_CONFIRMATION and MODAL_TYPE_NOTIFICATION
  • Finally when we want to show a modal somewhere in our code (maybe when the user tries to login, but the username / password  was incorrect, so there?) we simply use this.props.showModal(<modal type>, <props>)

Lets look at the example situation (which I also used in the example repository)

[gistpen id=”63″]

Final thoughts

So now you have a working and scalable implementation on how to use modals in your React, Redux application.

Another great reason why this solution is so great: you can now easily show a modal with different props everywhere, so if you want to show your designer a modal you have been working on: you simply call the action with its modal type + props and just like that it’s there.

Cheers

 

  • Dan Park

    I appreciate this post as there are so few in-depth code examples that reconcile react, react-redux, and redux with modals.

    I just have one design question:
    — Could you use your Modal component CSS template (with the preset styled divs) with different modal type designs? For example, it seems that your Modal templates assumes all modal types would appear in the center of the screen — however, what if you wanted to bring in a modal type that pops up from the bottom corner of the screen? I’ve been tinkering with the code and can’t seem to figure out a solution without touching the default Modal component code.

    Thanks in advance for your answer!

    • Mike Vercoelen

      Hi Dan Park, you just wrote the first reply on my blog, awesome, thanks for making the effort and I’m glad you liked the in-depth code examples.

      About your question: Yes, of course it’s possible, and it’s actually quite simple.

      Lets say we want to create a Modal that pop’s up from the bottom left corner. What I would do is modify the Modal component with a boolean property which triggers the special styling.

      Lets call this prop “isBottomLeft”, now on the Modal component where you are using the Modal you just add …

      Now the only thing you have to do is add the logic in the Modal component which actually sets the different styling when the property was submitted to the component.

      Ofcourse you don’t have to use styled-components, like I did, so feel free to use SCSS and add the classes based on the property etc.

      If you need more help, feel free to mail me at: mike.vercoelen@gmail.com. We could even do a Google Hangout sessions if you need even more help 😉

      Thanks again for the reply and I hope I made it more clear,

      Mike

      • Dan Park

        Ah, thats a very nice way of handling it! Thanks for your reply. Once again, wonderful blog!

        • Dan Park

          Hey Mike, just another question.

          What is the purpose of the Content Div?
          As I understand, it sits on top of the Overlay Div, providing positioning context for the Dialog Div. However, if you made the Dialog Div a direct child of the Overlay Div, wouldn’t it accomplish the same result?

          Thanks!

          • Mike Vercoelen

            Hi Dan, good question.

            The way it is setup, is I used a trick to horizontally / vertically center the div, which requires a wrapper div (which is in this case the Content div). You can read more about it here: https://css-tricks.com/centering-in-the-unknown/

            So there are different way in how you can set up the styling of the Modal component, it is totally up to you 😉

            Feel free to play around, and if you have more questions, ask ask ask.

            Mike

  • Diana

    Hi Mike,

    Thanks for this great writeup!

    I have a couple silly questions.

    The ModalRoot container expects an object with type and props, but it is rendered in the Application class with no arguments. How does the container get those values?

    Also in ModalRoot the connect call is made with a mapStateToProps of just ‘state => state.modal’. My react/redux knowledge is a bit lacking (probably js too), so I don’t understand what this does.

    • Pascal Heitz

      I also have that problem. I get `mapStateToProps() in Connect(ModalRoot) must return a plain object. Instead received undefined.`

      • Pascal Heitz

        I just found the solution to my problem.
        I indexed the modal reducer under the name of `modalReducer` and not `modal` as this demo shows. As a total beginner, it’s hard to solve those problems, as the logic is still pretty vague to me.
        Make sure of the key name you use in `combineReducers({…})` (in `store.js` probably).

  • Jude Alexis

    Hi Mike:

    Firstly, thank you for writing this article and for generating a fantastic example on Git. I’m somewhat new to React and Redux but I was able to follow your example. I would like to bring a couple of issues that I encountered to your attention:

    1. The app references ‘PropTypes’ from the core React Library. I am using a later version of React so the app fails to compile becuase PropTypes lives within the ‘prop-types’ package.
    2. The LoginView makes use of the @connect decorator to connect ShowModals to Redux. this also caused the app the fail. I was able to fix this by creating a MapDispatchToProps method and specifying the Show_Modal declaritively.

    I just wanted to highlight these items in case others had problems running the example.

    Thanks again,

    Jude

    • http://www.joaodias.me João Dias

      Hey Jude (pun intended 🙂 )

      Could you please be so kind to show an example of how you managed to create the MapDispatchToProps function, please?

      Thanks!

    • Mike Vercoelen

      Thanks for the reply, I’m a bit late hehe. I’m working on a new library called redux signal which is a solid solution for modals with Redux and React.

      I will create an article in the next few days about an explaination in more detail, but for now check out it out:

      https://github.com/mikevercoelen/redux-signal

  • hooplehead

    Doesn’t this involve storing functions in the Redux store (e.g. payload.onConfirm)? I thought that was a no-no in Redux, since they’re not serializable.

    • Mike Vercoelen

      Hey, thanks for the response. I just finished a new library for modals which solves this problem. I will create an article in the coming days with more info.

      For now you can check it out: https://github.com/mikevercoelen/redux-signal

  • fatih erol

    Hi Mike.. Thank you much..