2

I am building a Redux based Model/Dialog trigger based on Dan Abramov's solution to this question: Dan Abramov's solution

The error I am getting is "mapStateToProps() in Connect(ModalRoot) must return a plain object. Instead received undefined."


Here is the code for the modal container and the code that calls it:
// Code that calls the Modal Container

import React from 'react';
import { Provider } from 'react-redux';
import { Connector as HorizonConnector } from 'horizon-react';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

import routes from '../routes';
import store from '../store';
import horizon from '../db';
import ModalRoot from './Modal';

export default () => (
  <MuiThemeProvider muiTheme={getMuiTheme()}>
    <HorizonConnector horizon={horizon} store={store}>
      <div className="app">
        {routes}
        <ModalRoot />
      </div>
    </HorizonConnector>
  </MuiThemeProvider>
);

 // The Modal Container
 import LoginModal from '../components/Modals/LoginModal'
 import {connect} from 'react-redux'

const MODAL_COMPONENTS = {
  'LOGIN_MODAL': LoginModal
  /* other modals */
}

const ModalRoot = ({ modalType, modalProps }) => {
  if (!modalType) {
    return <span /> // after React v15 you can return null here
  }

  const SpecificModal = MODAL_COMPONENTS[modalType]
  return <SpecificModal {...modalProps} />
}

export default connect(
  state => state.modal
)(ModalRoot)


Its probably something simple i'm forgetting but its driving me crazy, any comments or suggestions welcome.
Community
  • 1
  • 1
Nathan Horrigan
  • 763
  • 1
  • 9
  • 20
  • Have you checked that the state.modal actually exists? Using redux dev tools? – ctrlplusb Jun 01 '16 at 22:05
  • Thanks for the response. Actually, it does not. Not really sure what I'm supposed to do to create it. Am I missing a step? – Nathan Horrigan Jun 01 '16 at 22:08
  • If you go through Dan's answer again you will see that you need to create a `modalReducer`, and then have fired actions that gets consumed by the reducer. If you are unfamiliar with redux, give Dan's lessons a go: https://egghead.io/series/getting-started-with-redux – ctrlplusb Jun 01 '16 at 22:11
  • Here is my actionCreators: [link](https://pastebin.mozilla.org/8874321) – Nathan Horrigan Jun 01 '16 at 22:15
  • Here is my reducer: [link](https://pastebin.mozilla.org/8874323) which is combined with combineRecucers – Nathan Horrigan Jun 01 '16 at 22:16
  • Reducer looks fine, your combineReducers implementation may be incorrect. – ctrlplusb Jun 01 '16 at 22:22
  • this is my index reducer which consists of the combineReducers function: [link](https://pastebin.mozilla.org/8874326) – Nathan Horrigan Jun 01 '16 at 22:32
  • Okay, again that looks good. Is your redux store being created before the rendering occurs? And is your app surrounded by the redux Provider component? – ctrlplusb Jun 01 '16 at 22:36
  • My project is built on the "Lovli.js" boilerplate for using Horizon and React/redux. Instead of using the Provider component it uses HorizonConnector from the horizon-react library that serves the same purpose as Provider. e.g passing the store down the hierarchy but it also does it with the horizon object – Nathan Horrigan Jun 01 '16 at 22:42
  • Awesome! I am just wanting to get into Horizon. I'll be keeping an eye on this. :) Hmmm... I would compare your init functions against the boilerplate. If they don't differ it may be worth pinging an issue on their github. – ctrlplusb Jun 01 '16 at 22:45
  • Yeah I think thats the only option at the moment, there doesn't seem to be any evidence of this happening anywhere else, also i dont think i mentioned this in the original post but this is crashing the page causing a white screen. – Nathan Horrigan Jun 01 '16 at 22:51
  • Actually after looking in Redux Dev Tools I can see that state.modal doesn't exist despite the modal reducer, any suggestions? – Nathan Horrigan Jun 01 '16 at 23:02

3 Answers3

3

According to redux implementation and example you should write like this

export default connect(
  state => ({
    modal: state.modal
  })
)(ModalRoot)

See here

Michael Rasoahaingo
  • 1,069
  • 6
  • 11
1

Perhaps mapStateToProps needs to pick a specific object from your reducer

Could you try something like this?

function mapStateToProps(state){
  const {modalType,modalProps} = state.modal;
  return {modalType,modalProps};
}

Its either this or perhaps you arent properly passing combineReducers to your store

Jayaram
  • 6,276
  • 12
  • 42
  • 78
0

The root cause of the problem is that state.modal is undefined. You can get more info by adding a simple log statement like:

export default connect(state => { console.log('state', state); return state.modal })(ModalRoot)

This may help you see what's in state and help in figuring out why state.modal is undefined.

To make this error go away, you can use either of these 2 solutions:

Ensuring the object is not undefined:

export default connect(state => state.modal || {})(ModalRoot)

Using ES6 destructuring:

export default connect(({ modal }) => ({ modal }))(ModalRoot)

If you use the ES6 destructuring (which is essentially same as @MichaelRasoahaingo's solution), your prop destructuring will also change to:

const ModalRoot = ({ modal: { modalType, modalProps } }) => {

Or you can use this alternative syntax and keep your destructuring as is:

export default connect(({ modal }) => ({ ...modal }))(ModalRoot)
Mrchief
  • 75,126
  • 20
  • 142
  • 189