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:
You don't update a component from another. Instead: components render from a shared top level data model. Callbacks are passed down to components. Any one of them can trigger a data change on that data model through the callbacks.
render() Calling setState() here makes it possible for a component to produce infinite loops. The render() function should be pure, meaning that it does not modify a component's state. It returns the same result each time it's invoked, and it does not directly interact with the browser.
React.memo is a higher order component. If your component renders the same result given the same props, you can wrap it in a call to React.memo for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result.
(1) While editing a component, you can't change the state of the component unless you click on the parent layer first.
This warning was introduced since React V16.3.0.
If you are using functional components you could wrap the setState call into useEffect.
Code that does not work:
const HomePage = (props) => { 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> ); };
Just coming here because I just had this issue and it took me a bit of digging around before I realised what I'd done wrong - I just wasn't paying attention to how I was writing my functional component.
Figured I'd leave an answer here in case anyone comes looking, and they made the same simple mistake that I did.
I 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 just forgotten to use useEffect
before dispatching my redux call of getDateMatches()
So stupid and something I had been doing in every other component, 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 took a while to realise it, so hopefully this helps out someone else with this issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With