I've got a SPA that has two parts, one of which allows you to choose a geographic area, and another which allows you to pick and choose countries. The country picker subscribes to the geographic area updates so that it can only put up countries that overlap your chosen geographic area. The problem happens when the render method on the CountryPanel attempts to remove countries from the selection if they are no longer in the selected geographic area. So if you select some countries in the eastern hemisphere in the CountryPanel, then go to the GeographicPanel and select an area in the western hemisphere, and the CountryPanel attempts to remove the selected countries from the store, I get the following error in the console:
Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
The problem occurs in a call to this.props.dispatch(removeCountry(c))
in the following code:
connect((store) => {
return {
min_lat_val: store.session.min_latitude_val,
min_lat_ns: store.session.min_latitude_ns,
max_lat_val: store.session.max_latitude_val,
max_lat_ns: store.session.max_latitude_ns,
min_long_val: store.session.min_longitude_val,
min_long_ew: store.session.min_longitude_ew,
max_long_val: store.session.max_longitude_val,
max_long_ew: store.session.max_longitude_ew,
sel_countries: store.session.selected_countries,
countries: store.extents.countries,
}
})
export class CountryPanel extends React.Component {
constructor(props) {
super(props)
}
render() {
let country_keys = Object.keys(this.props.countries).sort()
if (country_keys.length < 1) {
return <div class="panel-body">
<h3>Countries</h3>
<p className="strong">Country data has not loaded yet!</p>
</div>
}
let countries = []
if (this.props.min_lat_val && this.props.max_lat_val &&
this.props.min_long_val && this.props.max_long_val) {
let tuple = []
country_keys.forEach((c, i) => {
const country = this.props.countries[c]
if (extentsOverlap(
this.props.min_lat_val,
this.props.min_lat_ns,
this.props.max_lat_val,
this.props.max_lat_ns,
this.props.min_long_val,
this.props.min_long_ew,
this.props.max_long_val,
this.props.max_long_ew,
country)) {
tuple.push(<CountryCheck key={c} country={country} />)
if (tuple.length > 2) {
countries.push(tuple)
tuple = []
}
} else {
if (this.props.sel_countries.has(c)) {
this.props.dispatch(removeCountry(c))
}
}
})
if (tuple.length > 0) {
countries.push(tuple)
}
} else {
let tuple = []
country_keys.forEach((c, i) => {
tuple.push(<CountryCheck key={c} country={this.props.countries[c]} />)
if (tuple.length > 2) {
countries.push(tuple)
tuple = []
}
})
if (tuple.length > 0) {
countries.push(tuple)
}
}
const trs = countries.map((c, i) => <tr key={i}>{c}</tr>)
return <div class="panel-body">
<h3>Countries</h3>
<p>If you leave all the checkboxes unchecked, it will return waypoints in all countries that meet all the other criteria. If you select US or Canada, you will be able to select states or provinces from a further list below, or leave those checkboxes empty to select the whole country.</p>
<p>The two letter country codes you see below are from <a href="https://en.wikipedia.org/wiki/List_of_FIPS_country_codes">FIPS 10.4</a>, not the more common <a href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166</a>, which is why you might not recognize some of these codes.</p>
<p><strong>Note: Non-USA data is not as current as USA data, so carefully check this data.</strong> Actually, you should always check all this data against current official data sources.</p>
<table class="table table-striped table-bordered">
<tbody>
{trs}
</tbody>
</table>
</div>
}
}
If I try what's referred to as a "workaround and proof of concept" in https://stackoverflow.com/a/43438560/3333 and change the offending line to setTimeout(() => this.props.dispatch(removeCountry(c)), 0)
the warning goes away. Is that the best solution?