[英]React dispatching action in componentDidMount()
I've been trying to dispatch an action in componentDidMount, unfortunately I'm getting: 我一直在尝试在componentDidMount中调度一个动作,不幸的是,我得到了:
Maximum call stack size exceeded 超出最大呼叫堆栈大小
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import moment from 'moment';
import styles from './style.css';
import Arrow from './components/Arrow';
import RadioCheck from 'components/RadioCheck';
import Select from 'components/Select';
import DatePickerWrapper from 'components/DatePickerWrapper';
import { months } from 'utils';
import { changeMonth, changeFromDate, changeToDate, changeRadioDatepicker } from 'components/PostsPage/actions';
class DatePickerDropdown extends Component {
constructor(props) {
super(props);
this.firstChild = null;
this.state = {
open: false,
loadedPreferences: false,
};
this._handleSelectedClick = this._handleSelectedClick.bind(this);
this._handleRadioChange = this._handleRadioChange.bind(this);
this._handleFromDatepickerChange = this._handleFromDatepickerChange.bind(this);
this._handleToDatepickerChange = this._handleToDatepickerChange.bind(this);
this._handleMonthChange = this._handleMonthChange.bind(this);
this._handleOutsideClick = this._handleOutsideClick.bind(this);
}
componentDidMount() {
window.addEventListener('click', this._handleOutsideClick, false);
setTimeout(() => {
this.loadPreferences();
},5)
}
componentWillUnmount() {
window.removeEventListener('click', this._handleOutsideClick, false);
}
loadPreferences() {
const monthId = preferences.get(preferences.keys.DATEPICKER_MONTH);
const dateFrom = preferences.get(preferences.keys.DATEPICKER_FROM);
const dateTo = preferences.get(preferences.keys.DATEPICKER_TO);
const filterType = preferences.get(preferences.keys.DATEPICKER_FILTER_TYPE);
if (monthId !== null) {
this.props.changeMonth(monthId);
}
if (dateFrom !== null) {
this.props.changeFromDate(moment(dateFrom));
}
if (dateTo !== null) {
this.props.changeToDate(moment(dateTo));
}
if (filterType !== null) {
this.props.changeRadio(filterType);
}
}
getRange() {
const { datepickerFilter, month, dateFrom, dateTo} = this.props;
if (datepickerFilter === 'month') {
return {
start: moment().month(month).startOf('month').format('D. MMMM YYYY'),
end: moment().month(month).endOf('month').format('D. MMMM YYYY')
}
}
if (datepickerFilter === 'from_to') {
return {
start: dateFrom.format('D. MMMM YYYY'),
end: dateTo.format('D. MMMM YYYY'),
};
}
}
toggleSelect(show = null) {
if (show !== null) {
this.setState(() => ({open: show}));
}
if (show === null) {
this.setState(() => ({open: !this.state.open}));
}
}
_handleSelectedClick() {
this.toggleSelect();
}
_handleOutsideClick(e) {
if (!ReactDOM.findDOMNode(this).contains(e.target) && this.state.open) {
this.toggleSelect(false);
}
}
_handleFromDatepickerChange(date) {
if (this.props.dateFrom.toDate() !== date.toDate()) {
this.props.changeFromDate(date);
preferences.store(preferences.keys.DATEPICKER_FROM, date.toDate());
}
}
_handleToDatepickerChange(date) {
if (this.props.dateTo.toDate() !== date.toDate()) {
this.props.changeToDate(date);
preferences.store(preferences.keys.DATEPICKER_TO, date.toDate());
}
}
_handleMonthChange(month) {
if (this.props.month !== month) {
this.props.changeMonth(month);
preferences.store(preferences.keys.DATEPICKER_MONTH, month);
}
}
_handleRadioChange(filterType) {
if (this.props.datepickerFilter !== filterType) {
this.props.changeRadio(filterType);
preferences.store(preferences.keys.DATEPICKER_FILTER_TYPE, filterType);
}
}
render() {
const dropdownClass = this.state.open ? styles.dropdownActive : styles.dropdown;
const dropdownButtonClass = this.state.open ? styles.selectedActive : styles.selected;
const arrowClass = this.state.open ? styles.arrowActive : styles.arrow;
const range = this.getRange();
return (
<div className={styles.container}>
<div className={dropdownButtonClass} onClick={this._handleSelectedClick}>
<div className={styles.date}>{range.start}<span>to</span>{range.end}</div>
<div className={arrowClass}>
<Arrow up={this.state.open} size={10} invert={this.props.invert}/>
</div>
</div>
<div className={dropdownClass}>
<div className={styles.datepickerRow}>
<div>
<RadioCheck label={'Filter by Month'} type="radio" id="month" name="datepicker_radio" value="month" checked={this.props.datepickerFilter === 'month'} onChange={this._handleRadioChange}/>
</div>
<div className={styles.datepickerRowInner}>
<span>Month</span>
<div className={styles.inputItem}>
<Select
options={months}
onChange={this._handleMonthChange}
optionsToShow={12}
small
defaultOption={this.props.month.toString()}
/>
</div>
</div>
</div>
<div className={styles.datepickerRow}>
<div>
<RadioCheck label={'Filter by Date range'} type="radio" id="from" name="datepicker_radio" value="from_to" onChange={this._handleRadioChange} checked={this.props.datepickerFilter === 'from_to'}/>
</div>
<div className={styles.datepickerRowInner}>
<span>from</span>
<div className={styles.inputItem}>
<DatePickerWrapper date={this.props.dateFrom} onChange={this._handleFromDatepickerChange}/>
</div>
</div>
</div>
<div className={styles.datepickerRow}>
<div className={styles.datepickerRowInner}>
<span>to</span>
<div className={styles.inputItem}>
<DatePickerWrapper date={this.props.dateTo} onChange={this._handleToDatepickerChange}/>
</div>
</div>
</div>
</div>
</div>
);
}
}
DatePickerDropdown.propTypes = {};
DatePickerDropdown.defaultProps = {};
const mapStateToProps = state => {
const { monthSelect, dateFrom, dateTo, datepickerFilter } = state.postsFilters;
return {
month: monthSelect,
dateFrom,
dateTo,
datepickerFilter
}
};
const mapDispatchToProps = dispatch => {
return {
changeMonth: (monthId) => dispatch(changeMonth(monthId)),
changeFromDate: (date) => dispatch(changeFromDate(date)),
changeToDate: (date) => dispatch(changeToDate(date)),
changeRadio: (val) => dispatch(changeRadioDatepicker(val)),
}
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(DatePickerDropdown);
What I'm trying to achieve is to load preferences from localStorage. 我想要实现的是从localStorage加载首选项。 If i wrap the call of this.loadPreferences() in a setTimeout() with a delay of 100ms it does work, though that doesn't feel right. 如果我以100ms的延迟将this.loadPreferences()的调用包装在setTimeout()中,则它确实可以工作,尽管感觉不对。
I guess the issue stems from the fact that I'm updating the same props that I'm mapping to that component. 我猜这个问题源于我正在更新要映射到该组件的相同道具的事实。 What would be a better approach to achieve my goal? 有什么更好的方法可以实现我的目标?
EDIT: added whole source to avoid confusion 编辑:添加整个源,以避免混淆
尝试将点击处理程序显式绑定到上下文this._handleOutsideClick.bind(this)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.