Reputation: 16204
I have component as below:
const VIEW_PROFILE = 'profile'
const VIEW_SAA = 'saa'
const VIEW_DOCUMENTS = 'documents'
const VIEW_FINANCIERS = 'viewFinancierInfo'
class ViewFinancier extends Component {
constructor(props) {
super(props)
this.state = {
selectedNavigation: VIEW_PROFILE,
financierId: this.props.location.state.financierDetails.financierId,
defaultLoading: false
}
this.handleChangeNav = this.handleChangeNav.bind(this)
this.handleCancelButton = this.handleCancelButton.bind(this)
}
componentWillMount(props) {
this.props.loadFinancierProfile(this.props.location.state.financierDetails.financierId)
}
componentWillReceiveProps(newProps) {
this.setState({
defaultLoading: true,
viewfinancierprofiledata: newProps.viewfinancierprofiledata
})
}
handleChangeNav(e) {
var selectedNavigation = e.target.attributes.getNamedItem('value').value
this.setState({
selectedNavigation: selectedNavigation
})
}
handleCancelButton(changingState) {
this.setState({
selectedNavigation: changingState
})
}
render() {
if (this.state.defaultLoading === false) {
return (
<div className="tabledataloading tabletext">
Please wait while the data is loading <img alt="Loading..." src={loadingimg} />
</div>
)
} else if (this.state.selectedNavigation === VIEW_FINANCIERS) {
this.props.history.push('/financier/')
return null
} else {
return (
<div id="lesse-info-component-wrapper" className="melody-common-container">
<div id="header-wrapper">
<h1 className="melody-common-module-title">VIEW FINANCIER INFO</h1>
</div>
<div id="navigation-wrapper">
<ul id="add-financier-info-nav" className="topnavpad">
<li
value={VIEW_PROFILE}
onClick={this.handleChangeNav}
className={'add-financier-info-nav-item ' + (this.state.selectedNavigation === VIEW_PROFILE ? 'active' : '')}>
PROFILE
</li>
<li
value={VIEW_SAA}
onClick={this.handleChangeNav}
className={'add-financier-info-nav-item ' + (this.state.selectedNavigation === VIEW_SAA ? 'active' : '')}>
SAA
</li>
<li
value={VIEW_DOCUMENTS}
onClick={this.handleChangeNav}
className={'add-financier-info-nav-item ' + (this.state.selectedNavigation === VIEW_DOCUMENTS ? 'active' : '')}>
DOCUMENTS
</li>
</ul>
</div>
{this.state.selectedNavigation === VIEW_PROFILE
? <ViewFinancierProfile financierId={this.props.financierId} onCancelHandler={this.handleCancelButton} />
: null}
{this.state.selectedNavigation === VIEW_SAA
? <ViewFinancierSAA financierId={this.props.financierId} onCancelHandler={this.handleCancelButton} />
: null}
{this.state.selectedNavigation === VIEW_DOCUMENTS
? <ViewFinancierDocument financierId={this.props.financierId} onCancelHandler={this.handleCancelButton} />
: null}
</div>
)
}
}
}
const mapStateToProps = state => {
return {
viewfinancierprofiledata: state.viewfinancierprofiledata
}
}
const mapDispatchToProps = dispatch => {
return {
loadFinancierProfile: financierId => dispatch(viewFinancierProfileAction.loadFinancierProfile(financierId))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ViewFinancier)
And on execution I am getting the warning:Warning: setState(...): Cannot update during an existing state transition (such as within
renderor 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`
On looking into the console I found that the snippet this.props.history.push('/financier/')
is throwing the error.
On further research in other similar questions in Stack Overflow, I also found that this actually setting the parents state under render method, which is not allowed.
But now I cannot figure out how I can achieve the condition I am looking for.
Upvotes: 0
Views: 522
Reputation: 1478
Component props
should not be mutated by itself. I think there are 2 solutions for you in this situation.
this.props.history
to state
, and mutate history
by calling setState
. Put the checking of selectedNavigation
outside of render
. For example (just my idea, please modify it base on your application logical):class ViewFinancier extends Component {
constructor(props) {
super(props)
this.state = {
...
history = props.history,
...
}
...
}
componentWillReceiveProps(newProps) {
this.setState({
history: newProps.history,
...
})
}
handleChangeNav(e) {
var selectedNavigation = e.target.attributes.getNamedItem('value').value;
this.setState({
selectedNavigation: selectedNavigation
})
this.historyCheck(selectedNavigation);
}
handleCancelButton(changingState) {
this.setState({
selectedNavigation: changingState
});
this.historyCheck(changingState);
}
historyCheck(nav) {
if (nav === VIEW_FINANCIERS) {
history.push('/financier/');
};
this.setState(history: history);
}
render() {
...
} else if (this.state.selectedNavigation === VIEW_FINANCIERS) {
return null
}
...
}
}
this.props.history
is used by parent component also. Then you can pass a function to update history
from parent component and pass this function to your current (child) component.class ParentFinancier extends Component {
pushHistory => (val) {
let {history} = this.state;
this.setState(history: history.push('/financier/'));
}
render() {
...
<ViewFinancier pushHistory={this.pushHistory} ... />
}
...
}
class ViewFinancier extends Component {
...
} else if (this.state.selectedNavigation === VIEW_FINANCIERS) {
this.props.pushHistory('/financier/')
return null
}
...
}
...
Upvotes: 1