简体   繁体   中英

Confirmation modal connecting to redux store using mapStateToProps gives an ERROR

I have a modal component. When the close button of the modal is clicked, I need to show up a confirmation modal. It has yes and no options. This confirmataion component is connected to Redux store.

Everything was working fine till I connect the confirmation component into the store using mapStateToProps . After that only I started getting this error.

Error: Could not find "store" in either the context or props of "Connect(_class)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(_class)". at invariant (bundle.js:21701)

I have attached the image below.

在此输入图像描述

Here's my confirmation modal.

import React, { Component, PropTypes } from 'react';
import AriaModal from 'react-aria-modal';
import { confirm } from '../util/confirm';
import { confirmable } from 'react-confirm';

class Confirmation extends Component {
  constructor(props) {
    super(props);
    this.getApplicationNode = this.getApplicationNode.bind(this);
  }

  getApplicationNode = () => {
    return document.getElementById('application');
  }

  render() {
    console.log("rendering confirmation....");
    const {
     okLabbel = 'OK',
     cancelLabel = 'Cancel',
     title,
     confirmation,
     show,
     proceed,
     dismiss,
     cancel,
     enableEscape = true,
   } = this.props;

    const modal =
        <AriaModal
          titleText="demo one"
          onExit={this.deactivateModal}
          mounted={this.props.modalActive}
          initialFocus="#demo-one-deactivate"
          getApplicationNode={this.getApplicationNode}
          underlayStyle={{ paddingTop: '2em' }}
        >
          <div id="test-modal" className="background">
            <div className='model-title'>
              <h3 className='pe-title'>{title}</h3>
            </div>
            <div className="modal-body">
              {confirmation}
            </div>
            <footer className="modal-footer">
              <button className="btn btn-info" onClick={cancel}>{cancelLabel}</button>
              <button className='btn btn-danger' onClick={proceed}>{okLabbel}</button>
            </footer>
          </div>
        </AriaModal>;

    return (
      <div>
        {modal}
      </div>
    );
  }

}

Confirmation.propTypes = {
  okLabbel: PropTypes.string,
  cancelLabel: PropTypes.string,
  title: PropTypes.string,
  confirmation: PropTypes.string,
  show: PropTypes.bool,
  proceed: PropTypes.func,     // called when ok button is clicked.
  cancel: PropTypes.func,      // called when cancel button is clicked.
  dismiss: PropTypes.func,     // called when backdrop is clicked or escaped.
  enableEscape: PropTypes.bool,
}

export default confirmable(Confirmation);

This is how I connected it to the store in a container component.

import { connect } from 'react-redux';
import Confirmation from '../components/Confirmation';

const mapStateToProps = (state) => {
  console.log("Calling mapStateToProps here!" + state.confirmation.modalActive);
  return { modalActive: state.confirmation.modalActive };
}

export default connect(mapStateToProps)(Confirmation);

You may see in the console the initial actioin on setting the visibility to true is working fine and the action is logged in the console like this.

{type: ON_CONFIRM, payload: true}

What's wrong with this mapStateToProps ?

You may find the code for the project here .

Why I am getting this error. What is going wrong here? Any help is appreciated.

The problem is in the react-confirm library. It renders your confirmation model in it's own component tree and not in your application's component tree. If you look at its source code , you can see that it use ReactDOM.render internally to create a new component tree. It's like you have two React application on the same page.

mapStateToProps of react-redux use React context to access the store. But as connected Confirmation component is rendered in a different component tree, connect HoC can't access the redux store via context.

The simplest solution would be finding another library which doesn't have this problem. But alternatively, you can inject your context manually into your connected Confirmation using a HoC.

Here is a HoC which you can use to inject the context to a component:

function withContext(WrappedComponent, context){

  class ContextProvider extends React.Component {
    getChildContext() {
      return context;
    }

    render() {
      return <WrappedComponent {...this.props} />
    }
  }

  ContextProvider.childContextTypes = {};
  Object.keys(context).forEach(key => {
    ContextProvider.childContextTypes[key] = React.PropTypes.any.isRequired; 
  });

  return ContextProvider;
}

Let's assume that you render your connected Confirmation component in a component call Page. Then you can inject the context using above HoC like this.

class Page extends React.Component {

  //......

  static contextTypes = {
    store: React.PropTypes.object.isRequired
  }

  render(){

    const ConfirmationWithContext = withContext(ConnectedConfirmation, this.context);

    return (
      //.....
      <ConfirmationWithContext/> // with your props
      //.....
    );
  }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM