thanks_in_advance
thanks_in_advance

Reputation: 2743

"Cannot update during an existing state transition" error in React

I'm trying to do Step 15 of this ReactJS tutorial: React.js Introduction For People Who Know Just Enough jQuery To Get By

The author recommends the following:

overflowAlert: function() {
  if (this.remainingCharacters() < 0) {
    return (
      <div className="alert alert-warning">
        <strong>Oops! Too Long:</strong>
      </div>
    );
  } else {
    return "";
  }
},

render() {
  ...

  { this.overflowAlert() }

  ...
}

I tried doing the following (which looks alright to me):

// initialized "warnText" inside "getInitialState"


overflowAlert: function() {
  if (this.remainingCharacters() < 0) {
    this.setState({ warnText: "Oops! Too Long:" });
  } else {
    this.setState({ warnText: "" });
  }
},

render() {
  ...

  { this.overflowAlert() }
  <div>{this.state.warnText}</div>

  ...
}

And I received the following error in the console in Chrome Dev Tools:

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.

Here's a JSbin demo. Why won't my solution work and what does this error mean?

Upvotes: 22

Views: 57895

Answers (5)

Nadimuthu Sarangapani
Nadimuthu Sarangapani

Reputation: 316

Call the component props at each time as new render activity. Warning occurred while overflow the single render.

instead of
<Item onPress = { props.navigation.toggleDrawer() } />
try like
<Item onPress = {() =>  props.navigation.toggleDrawer() } />

Upvotes: 0

Andrew Li
Andrew Li

Reputation: 57934

Your solution does not work because it doesn't make sense logically. The error you receive may be a bit vague, so let me break it down. The first line states:

Cannot update during an existing state transition (such as within render or another component's constructor).

Whenever a React Component's state is updated, the component is rerendered to the DOM. In this case, there's an error because you are attempting to call overflowAlert inside render, which calls setState. That means you are attempting to update state in render which will in then call render and overflowAlert and update state and call render again, etc. leading to an infinite loop. The error is telling you that you are trying to update state as a consequence of updating state in the first place, leading to a loop. This is why this is not allowed.

Instead, take another approach and remember what you're trying to accomplish. Are you attempting to give a warning to the user when they input text? If that's the case, set overflowAlert as an event handler of an input. That way, state will be updated when an input event happens, and the component will be rerendered.

Upvotes: 54

daRula
daRula

Reputation: 143

You can also define the function overflowAlert: function() as a variable like so and it will not be called immediately in render

overflowAlert = ()=>{//.....//}

Upvotes: -1

azwar_akbar
azwar_akbar

Reputation: 1651

Make sure you are using proper expression. For example, using:

<View onPress={this.props.navigation.navigate('Page1')} />

is different with

<View onPress={ () => this.props.navigation.navigate('Page1')} />

or

<View onPress={ () => {
    this.props.navigation.navigate('Page1')
}} />

The two last above are function expression, the first one is not. Make sure you are passing function object to function expression () => {}

Upvotes: 9

Basheer Kohli
Basheer Kohli

Reputation: 164

Instead of doing any task related to component in render method do it after the update of component In this case moving from Splash screen to another screen is done only after the componentDidMount method call.

import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Button,
Image,
} from 'react-native';


let timeoutid;

export default class Splash extends Component {

static navigationOptions = {
navbarHidden: true,
tabBarHidden: true,
};

constructor(props) {
super(props)
this.state = { navigatenow: false };

 }
 componentDidMount() {
 timeoutid=setTimeout(() => {
   this.setState({ navigatenow: true });
 }, 5000);
}
 componentWillUnmount(){

 clearTimeout(timeoutid);
}
componentDidUpdate(){
const { navigate,goBack } = this.props.navigation;

if (this.state.navigatenow == true) {

  navigate('Main');
}
}
render() {

//instead of writing this code in render write this code in 
 componenetDidUdpate method 
/* const { navigate,goBack } = this.props.navigation;

if (this.state.navigatenow == true) {

  navigate('Main');
}*/

return (

  <Image style={{
    flex: 1, width: null,
    height: null,
    resizeMode: 'cover'
  }} source={require('./login.png')}>
  </Image>
);

  }
}

Upvotes: 0

Related Questions