I have a YearFilter component:
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Dropdown } from 'semantic-ui-react';
import {
changeYear
} from '../../actions/menuFiltersActions';
import makeDropdownOptions from '../../lib/makeDropdownOptions';
export class YearFilter extends React.Component {
constructor(props) {
super(props);
this.handleChangeYear = this.handleChangeYear.bind(this)
}
handleChangeYear(year) {
console.log(year)
this.props.changeYear(year)
this.props.getClientActuals()
// this.props.testSelectedYear()
console.log(this.props.years.selectedYear)
}
render() {
return (
<div id="YearFilter">
<span>Year</span>
<Dropdown
// fluid
selection
loading={!this.props.years.data.length}
options={makeDropdownOptions(this.props.years.data)}
value={this.props.years.selectedYear}
onChange={(e, { value }) => this.handleChangeYear(value)}
/>
</div>
);
}
}
YearFilter.propTypes = {
years: PropTypes.exact({
data: PropTypes.array,
selectedYear: PropTypes.number
}).isRequired,
changeYear: PropTypes.func.isRequired,
getClientActuals: PropTypes.func.isRequired,
};
export default connect(
store => ({
years: store.menuFilters.years
}),
{
changeYear
}
)(YearFilter);
I am using this to update the menuFilters.years.selectedYear property in the Redux store whenever the user selects a year from the dropdown.
The parent component is the following:
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Header, Button, Icon, Loader} from 'semantic-ui-react';
import {
changeYear
} from '../../actions/menuFiltersActions';
import {
saveSalesHouseForecastSpendData
} from '../../actions/forecastSpendDataActions';
import './TabDataEntry.css';
import DataEntryFiltersSidebar from '../DataEntryFiltersSidebar/DataEntryFiltersSidebar';
import YearFilter from '../YearFilter/YearFilter';
import PivotTable from '../PivotTable/PivotTable';
import PivotTableAPI from '../../api/PivotTableAPI';
import processForecastSpendData from '../../lib/processForecastSpendData';
import { SALESHOUSE_LEVEL, MONTHS } from '../../constants';
export class TabDataEntry extends React.Component {
constructor(props) {
super(props);
this.state = {
isSavingChanges: false,
showNotification: false,
showPivotTable: false
}
this.getClientActuals = this.getClientActuals.bind(this);
this.getClientActualsFilters = this.getClientActualsFilters.bind(this);
this.saveForecasts = this.saveForecasts.bind(this);
this.collectChangedForecasts = this.collectChangedForecasts.bind(this);
this.testSelectedYear = this.testSelectedYear.bind(this);
}
componentDidUpdate(prevProps) {
if (prevProps.menuFilters.years.data !== this.props.menuFilters.years.data){
this.props.changeYear(this.props.menuFilters.years.data[0]);
}
}
getClientActualsFilters(extraParams) {
const filters = {
year: this.props.menuFilters.years.selectedYear,
client_id: this.props.menuFilters.brands.selectedBrand,
...extraParams
};
// console.log(filters)
if (this.props.menuFilters.media.selectedMedia) {
filters.media_id = this.props.menuFilters.media.selectedMedia;
}
if (this.props.menuFilters.media.selectedBooking) {
filters.booking_id = this.props.menuFilters.media.selectedBooking;
}
return filters;
}
testSelectedYear(){
console.log(this.props.menuFilters.years.selectedYear)
}
async getClientActuals() {
try {
const clientActuals = await PivotTableAPI.getClientActuals(this.getClientActualsFilters());
this.props.saveSalesHouseForecastSpendData(
processForecastSpendData(clientActuals, { level: SALESHOUSE_LEVEL })
);
this.setState({showPivotTable: true})
} catch (e) {console.log(e)}
}
async saveForecasts() {
this.setState({ isSavingChanges: true })
let forecast = this.collectChangedForecasts(this.props.forecastSpendData);
try {
const response = await PivotTableAPI.saveForecasts({
media_id: this.props.menuFilters.media.selectedMedia,
booking_id: this.props.menuFilters.media.selectedBooking,
advertiser_id: this.props.menuFilters.brands.selectedBrand,
year: this.props.menuFilters.years.selectedYear,
forecast_period: [],
forecast
});
this.notify(response ? 'positive' : 'negative');
} catch (e) { console.log(e) }
this.setState({ isSavingChanges: false })
}
collectChangedForecasts(data) {
const childrenKeys = {
Saleshouse: 'folios',
Folio: 'suppliers'
};
let changedForecasts = Object.values(data).reduce((changedForecasts, saleshouse) => {
for (let month in MONTHS) {
// check if forecast has changed and if this element is the level at which data was entered
if (saleshouse[MONTHS[month]]
&& saleshouse[MONTHS[month]].changed
&& saleshouse[MONTHS[month]].forecastLevel === saleshouse.level) {
changedForecasts.push({
month: parseInt(month) + 1,
sales_house_id: saleshouse.SaleshouseId,
folio_id: saleshouse.FolioId,
supplier_id: saleshouse.SupplierId,
forecast_level: saleshouse[MONTHS[month]].forecastLevel,
metric: saleshouse[MONTHS[month]].forecast
});
}
}
let children = saleshouse[ childrenKeys[saleshouse.level] ]
if (children && Object.values(children).length) {
changedForecasts.push(...this.collectChangedForecasts(children))
}
return changedForecasts;
}, [])
return changedForecasts
}
notify(state) {
this.setState({ showNotification: state })
setTimeout(() => this.setState({ showNotification: false }), 5000)
}
render() {
return (
<div id="TabDataEntry">
<DataEntryFiltersSidebar
getClientActuals={this.getClientActuals}
/>
<div id="main-container">
<div className="header-section">
<Header as="h2">Investment forecasts</Header>
<p>
Select a Client / Advertiser to view and confirm the current share deal spends.
<Loader as="span" active={this.state.isSavingChanges} inline size="mini" inverted />
{ this.state.showNotification &&
<span className={`notification ${this.state.showNotification}`}><Icon name="checkmark"/>Saved</span>
}
</p>
</div>
{this.state.showPivotTable &&
<>
<YearFilter
getClientActuals={this.getClientActuals}
testSelectedYear={this.testSelectedYear}
/>
<div id="overflowing-container">
<PivotTable
getClientActualsFilters={this.getClientActualsFilters}
/>
<div id="bottom-buttons">
<div>
<Button
primary
onClick={this.saveForecasts}
disabled={!Object.keys(this.props.forecastSpendData).length}
>
<Loader active={this.state.isSavingChanges} inline size="mini" inverted /> Save Changes
</Button>
<Button
basic
onClick={this.getClientActuals}
disabled={!Object.keys(this.props.forecastSpendData).length}
>
Cancel
</Button>
</div>
<Button basic disabled><Icon name='balance scale'/>Rebalance Calculator</Button>
<Button basic disabled><Icon name='file excel outline'/>Export as XLS</Button>
</div>
</div>
</>
}
</div>
</div>
);
}
}
TabDataEntry.propTypes = {
menuFilters: PropTypes.objectOf(PropTypes.object).isRequired,
forecastSpendData: PropTypes.objectOf(PropTypes.object).isRequired,
saveSalesHouseForecastSpendData: PropTypes.func.isRequired,
changeYear: PropTypes.func.isRequired
};
export default connect(
store => ({
menuFilters: store.menuFilters,
forecastSpendData: store.forecastSpendData
}),
{ saveSalesHouseForecastSpendData, changeYear }
)(TabDataEntry);
The problem I am having is that when YearFilter updates the menuFilters.years.selectedYear in the Redux store, the parent component (TabDataEntry) still retrieves the previously set value.
What am I doing wrong? Appreciate any help.