如何从布局容器中触发react-modal?

时间:2017-07-23 15:21:43

标签: reactjs react-router react-redux react-router-redux react-modal

我正努力在我的React + Redux + ReactRouter4应用程序中使用react-modal

我有一个MainLayout容器和一个Home容器。

只有在渲染主容器时才会使用模态,因此我在主容器中有ReactModal的逻辑。我可以像这样轻松地从Home Container打开模态:

<button onClick={this.openModal}>Open Modal</button>

问题是MainLayout容器有一个导航,也需要能够打开模态,但很明显,this.openModal在那里不存在...我如何允许MainLayout容器打开Home容器中的模态?

class Home extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      modalIsOpen: false
    };
    this.openModal = this.openModal.bind(this);
    this.closeModal = this.closeModal.bind(this);

  }

  openModal() {
    this.setState({modalIsOpen: true});
  }

  closeModal() {
    this.setState({modalIsOpen: false});
  }

  render() {
    return (
      <div>
        ....
        <button onClick={this.openModal}>Open Modal</button>

        <Modal
          isOpen={this.state.modalIsOpen}
          onAfterOpen={this.afterOpenModal}
          onRequestClose={this.closeModal}
          style={modalCustomStyles}
          contentLabel="Example Modal"
        >
          <h2 ref={subtitle => this.subtitle = subtitle}>Hi</h2>
          <button onClick={this.closeModal}>close</button>
          <div>I am a modal</div>
        </Modal>

      </div>
    )
  };

};

App.jsx

const WithMainLayout = ({component: Component, ...more}) => {
  return <Route {...more} render={props => {
    return (
      <MainLayout {...props}>
        <Component {...props} />
      </MainLayout>
    );
  }}/>;
};    
....
<WithMainLayout exact path="/" component={Home} />

1 个答案:

答案 0 :(得分:1)

我要做的只是将modalOpenState移动到redux而不是将其保持在本地状态。你的初始状态就是这样。

export default {
  modalIsOpen: false
};

然后编写一个动作来切换商店中的模态状态。

export function toggleQuestionModal(isOpen) {
  return { type: types.TOGGLE_QUESTION_MODAL, payload: isOpen };
}

你对模态的表达部分应该是这样的。

import React, { Component, PropTypes } from 'react';
import Modal from 'react-modal';

const QuestionModal = ({ modalIsOpen, openModal, closeModal, afterOpenModal }) => {
  const customStyles = {
    overlay: {
      position: 'fixed',
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      backgroundColor: 'rgba(0, 0, 0, 0.75)'
    },

    content: {
      top: '50%',
      left: '50%',
      right: 'auto',
      bottom: 'auto',
      marginRight: '-50%',
      height: '50%',
      width: '80%',
      transform: 'translate(-50%, -50%)'
    }
  };

  return (
    <div>
      <button onClick={openModal}>Open Modal</button>
      <Modal
        isOpen={modalIsOpen}
        onAfterOpen={afterOpenModal}
        onRequestClose={closeModal}
        style={customStyles}
        contentLabel="Create A Question"
        role="dialog"
      >

        <h2>Hello</h2>
        <button onClick={closeModal}>close</button>
        <div>I am a modal</div>
        <form>
          <input />
          <button>tab navigation</button>
          <button>stays</button>
          <button>inside</button>
          <button>the modal</button>
        </form>
      </Modal>
    </div>
  );
};

QuestionModal.propTypes = {
  modalIsOpen: PropTypes.bool.isRequired,
  openModal: PropTypes.func.isRequired,
  closeModal: PropTypes.func.isRequired,
  afterOpenModal: PropTypes.func.isRequired
};

export default QuestionModal;

最后,这是模态的容器组件。

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { toggleQuestionModal, toggleConfirmation } from '../actions/questionActions';
import QuestionModal from '../components/questionModal';

class QuestionPage extends Component {
    constructor(props, context) {
        super(props, context);
        this.openModal = this.openModal.bind(this);
        this.closeModal = this.closeModal.bind(this);
        this.afterOpenModal = this.afterOpenModal.bind(this);
    }


    openModal() {
        this.props.toggleQuestionModal(true);
    }

    afterOpenModal() {
        // references are now sync'd and can be accessed. 
        // this.subtitle.style.color = '#f00';
    }

    closeModal() {
        this.props.toggleConfirmation(true);
    }

    render() {
        const { modalIsOpen } = this.props;
        return (
            <div>
                <QuestionModal modalIsOpen={modalIsOpen} openModal={this.openModal} closeModal={this.closeModal} 
                afterOpenModal={this.afterOpenModal} />
            </div>
        );
    }
}

QuestionPage.propTypes = {
    modalIsOpen: PropTypes.bool.isRequired,
    toggleQuestionModal: PropTypes.func.isRequired,
};

function mapStateToProps(state, ownProps) {
    return {
        modalIsOpen: state.question.modalIsOpen
    };
}

function mapDispatchToProps(dispatch) {
    return {
        toggleQuestionModal: bindActionCreators(toggleQuestionModal, dispatch),
    };
}

export default connect(mapStateToProps, mapDispatchToProps)(QuestionPage);

如果要从任何组件打开模态,只需使用true值调用toggleQuestionModal操作。这将改变状态并渲染模态。 Redux建议将所有内容保持在状态。我这样做。不要把事情保持在当地。保持一切状态使您可以更轻松地使用工具进行时间旅行调试。您可以找到示例实现here。希望这可以帮助。快乐的编码!