Как запустить реагировать на модал из макета контейнера?
Я работаю, чтобы использовать реактивный модал в моем приложении React+Redux+ReactRouter4.
У меня есть контейнер 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 ответ
То, что я хотел бы сделать, это просто переместить modalOpenState в избыточный код, а не сохранять его в локальном состоянии. Ваше начальное состояние будет таким.
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);
Когда вы хотите открыть модальный из любого компонента, просто вызовите toggleQuestionModal
действие с истинным значением. Это изменит состояние и сделает модальный. Redux рекомендует держать все в состоянии. Я практикую это. Не держите вещи местными. Сохранение всего в состоянии облегчает вам отладку путешествий во времени с помощью инструментов. Вы можете найти пример реализации здесь. Надеюсь это поможет. Удачного кодирования!