22

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?

2
  • 5
    Think about it: a component is rerendered when state is updated, so if you update state in a render method, it'll be an infinite loop. What are you trying to accomplish here? Update the state whenever someone inputs text or something. Commented Mar 12, 2017 at 8:23
  • @AndrewLi Lucid answer. Go ahead and file it as an answer and I'll mark it correct. What am I trying to accomplish here: well I was trying to do it my own way without looking at the solution, and this was what I came up with. Commented Mar 12, 2017 at 8:33

5 Answers 5

54

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.

Sign up to request clarification or add additional context in comments.

Comments

9

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 () => {}

Comments

0

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>
);

  }
}

1 Comment

this solved my problem, but I don't understand why. Can you explain?
0

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() } />

1 Comment

<Item onPress = {props.navigation.toggleDrawer} />
-1

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.