I am using react modal to set up a pop up in on one of my components. I have a component that renders a div wrapped with react modal. My parent component renders the modal component on load with the isOpen set to false. Clicking a link on the parent sets isOpen to true and causes the modal popup to open.
I make changes to my data within the open popup and then save the changes and close the model when the close button is clicked.
I am using a redux set up with actions and reducers handling the data changes and state changes.
Conceptually, how would I update the parent to show the changes made from the popup? Shouldn't changes to my data using an action cause the store to regenerate and hence update the data in my components or do I have to explicitly "refresh" my store after saving? My issue is that right now when the popup closes it is not tirggering any kind of "refresh" on the DataView component.
Components below:
DataView component
import React from 'react';
import DataView from './MonthView.js';
import DataViewPopup from './MonthViewPopup.js';
import { connect } from 'react-redux';
import { getAction } from '../actions/actions.js';
import { getActionAll } from '../actions/actions.js';
import { getPopupData } from '../actions/actions.js';
class DataViewContainer extends React.Component {
constructor() {
super();
this.popupCategory = undefined;
this.popupMonth = undefined;
this.state = {
detailPopup : false,
refreshView: false
}
this.handleAddYear = this.handleAddYear.bind(this);
this.handleSubtractYear = this.handleSubtractYear.bind(this);
this.handleGetDetail = this.handleGetDetail.bind(this);
}
componentDidMount() {
this.props.getAction(2016);
this.props.getActionAll(2016);
}
render() {
return (
<div className="row">
<div className="col-sm-8">
<MonthView transactions={this.props.storeData.storeData} selectedYear={this.props.storeData.selectedYear} onAddYear={this.handleAddYear} onSubtractYear={this.handleSubtractYear} onHandleGetDetail={this.handleGetDetail} />
</div>
<div className="col-sm-4">
<MonthViewPopup modalActive={this.state.detailPopup} transactions={this.props.storePopupData.getPopupData} selectedYear={this.props.storeTransactions.selectedYear} category={this.popupCategory} month={this.popupMonth}/>
</div>
</div>
)
}
handleGetDetail(category,month) {
console.log("props inside handleGetDetail: ", this.props);
this.popupCategory = category;
this.popupMonth = month;
let popupYear = this.props.storeTransactions.selectedYear
this.props.getPopupData(popupYear, month, category);
this.setState({ detailPopup: true}, function () {});
}
}
const mapStateToProps = (state) => ({
storeData: state.storeData,
storePopupData: state.storePopupData,
storeDataAll: state.storeDataAll
});
export default connect(mapStateToProps, {getAction,getActionAll,getPopupData})(DataViewContainer);
DataViewPopup component
import React from 'react';
import Modal from 'react-modal';
import { connect } from 'react-redux';
import { saveAction } from '../actions/actions.js';
import { getActionAll } from '../actions/actions.js';
class DataViewPopup extends React.Component {
constructor (props) {
super(props)
this.editedData = new Map();
this.state = {
modalIsOpen: false
};
this.openModal = this.openModal.bind(this);
this.afterOpenModal = this.afterOpenModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.renderFilteredTransactions = this.renderFilteredTransactions.bind(this);
}
openModal() {
this.setState({modalIsOpen: true});
}
afterOpenModal () {
console.log("inside afterOpenModal");
}
closeModal () {
this.props.saveTransactions(this.editedData);
this.editedData = new Map();
this.setState({ modalIsOpen: false }, function () {});
}
componentWillUnmount() {
this.props.getDataAll(); // i tried this but it does not work because the component (modal popup) is still mounted, but just not visible
//this.props.refreshParent();
}
componentWillReceiveProps(nextProps){
if (nextProps.modalActive === true) {
this.openModal();
return;
}
}
render () {
return <div>
<Modal
isOpen={this.state.modalIsOpen}
//isOpen={this.modalActive}//not needed as is currently setup
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
//style={customStyles}
contentLabel="Example Modal"
>
<button onClick={this.closeModal}>close</button>
{this.renderFilteredTransactions(this.props.data,this.props.category,this.props.month)};
</Modal>
</div>
}
renderFilteredTransactions(trans,category,month){
return <div>
<table>
<tbody className="mo-tblBody">
{trans && trans.map((data,index) =>
<tr key={data.transid}>
<td>{data.transid}</td>
<td>
{this.renderCategory(data.category,index,data.transid)}
</td>
</tr>
)}
</tbody>
</table>
</div>
}
handleCategoryChange(value,transIndex,transId){
let trans = JSON.parse(JSON.stringify(this.props.transactions));
//add or updated transaction to this.editedTransactions based on whether or not the transid already exists
trans.filter(item => item.transid === transId)
.map(item => this.editedData.set(transId,
Object.assign({}, item, { category: value })));
}
}
const mapStateToProps = (state) => {
return {storeDataAll: state.storeDataAll,
storeSaveData: state.storeSaveData
}
};
export default connect(mapStateToProps, {getDataAll,saveData})(DataViewPopup);
I covered this kind of question in my recent post Practical Redux, Part 10: Managing Modals and Context Menus.
The basic approaches are: