I am getting this warning in react:
index.js:1 Warning: Cannot update a component (`ConnectFunction`)
while rendering a different component (`Register`). To locate the
bad setState() call inside `Register`
I went to the locations indicated in the stack trace and removed all setstates but the warning still persists. Is it possible this could occur from redux dispatch?
my code:
register.js
class Register extends Component {
render() {
if( this.props.registerStatus === SUCCESS) {
// Reset register status to allow return to register page
this.props.dispatch( resetRegisterStatus()) # THIS IS THE LINE THAT CAUSES THE ERROR ACCORDING TO THE STACK TRACE
return <Redirect push to = {HOME}/>
}
return (
<div style = {{paddingTop: "180px", background: 'radial-gradient(circle, rgba(106,103,103,1) 0%, rgba(36,36,36,1) 100%)', height: "100vh"}}>
<RegistrationForm/>
</div>
);
}
}
function mapStateToProps( state ) {
return {
registerStatus: state.userReducer.registerStatus
}
}
export default connect ( mapStateToProps ) ( Register );
function which triggers the warning in my registerForm component called by register.js
handleSubmit = async () => {
if( this.isValidForm() ) {
const details = {
"username": this.state.username,
"password": this.state.password,
"email": this.state.email,
"clearance": this.state.clearance
}
await this.props.dispatch( register(details) )
if( this.props.registerStatus !== SUCCESS && this.mounted ) {
this.setState( {errorMsg: this.props.registerError})
this.handleShowError()
}
}
else {
if( this.mounted ) {
this.setState( {errorMsg: "Error - registration credentials are invalid!"} )
this.handleShowError()
}
}
}
Stacktrace:
This warning was introduced since React V16.3.0.
If you're using functional components, you can wrap the setState call in useEffect.
Code that doesn't work:
const HomePage = (props) => { trigger on component mount useEffect(() => { props.setAuthenticated(true); }, []); const handleChange = (e) => { props.setSearchTerm(e.target.value.toLowerCase()); }; return ( <div key={props.restInfo.storeId} className="container-fluid"> <ProductList searchResults={props.searchResults} /> </div> ); };Now you can change it to:
const HomePage = (props) => { trigger on component mount useEffect(() => { props.setAuthenticated(true); }, []); const handleChange = (e) => { props.setSearchTerm(e.target.value.toLowerCase()); }; return ( <div key={props.restInfo.storeId} className="container-fluid"> <ProductList searchResults={props.searchResults} /> </div> ); };incorrect
I only came here because I had this problem and it took me a bit of digging before I realized what I had done wrong: I just wasn't paying attention to how I was writing my functional component.
I thought I'd leave an answer here in case someone else came looking, and they made the same simple mistake I did.
was doing this:
const LiveMatches = (props: LiveMatchesProps) => { const { dateMatches, draftingConfig, sportId, getDateMatches, } = props; if (!dateMatches) { const date = new Date(); getDateMatches({ sportId, date }); }; return (<div>{component stuff here..}</div>); }; I had forgotten to use useEffect before submitting my getDateMatches() redux call
So stupid and something that I had been doing in all the other components, haha.
So it should have been:
const LiveMatches = (props: LiveMatchesProps) => { const { dateMatches, draftingConfig, sportId, getDateMatches, } = props; useEffect(() => { if (!dateMatches) { const date = new Date(); getDateMatches({ sportId, date }); } }, [dateMatches, getDateMatches, sportId]); return (<div>{component stuff here..}</div>); };Simple and silly mistake, but it took a while to figure out, so I hope this helps someone else with this problem.
The problem is corrected
I fixed this issue by removing the dispatch from the register components render method to the componentwillunmount method. This is because I wanted this logic to occur right before redirecting to the login page. In general it's best practice to put all your logic outside the render method so my code was just poorly written before. Hope this helps anyone else in future :)
My refactored register component:
class Register extends Component {
componentWillUnmount() {
// Reset register status to allow return to register page
if ( this.props.registerStatus !== "" ) this.props.dispatch( resetRegisterStatus() )
}
render() {
if( this.props.registerStatus === SUCCESS ) {
return <Redirect push to = {LOGIN}/>
}
return (
<div style = {{paddingTop: "180px", background: 'radial-gradient(circle, rgba(106,103,103,1) 0%, rgba(36,36,36,1) 100%)', height: "100vh"}}>
<RegistrationForm/>
</div>
);
}
}