Oliver D
Oliver D

Reputation: 2889

How to solve Cannot update during an existing state issue - react?

I have a function I calling it in render() method and it's setState a Flag from the state.

So I got this error

Cannot update during an existing state transition (such as within render).

I read about this error, and what I understand it's because I setState in render method and this is the wrong way.

So I'm forced to do it if u have any idea to handle this tell me.

The main idea about this function

I have an array of an object "Name as Tools" so in every object I have "id, name, count, price" so that will render a three input in UI like this

UI

and I have a boolean flag in-state "isEmpty" that checks every input in array before sending this data to the database.

Code

State = {
   toolsUsed: [
      {
        id: 0,
        name: '',
        price: '',
        count: '',
      },
    ],
    // Checker
    isEmpty: false,
}

renderToolsUsed = () => {
  const {toolsUsed} = this.state;
  const tools = toolsUsed.map((item, i) => {
  const {count, price, name, id} = item;
  this.setState({
     isEmpty: ['name', 'price', 'count'].every(key => item[key].length > 0),
   });
   return (
      <View key={i} style={styles.tools}>
         .... Inputs here ...
      </View>
   );
 });
 return tools;
};

JSX

render() {
    return (
       <View>
           {this.renderToolsUsed()}
       </View>
     );
}

Upvotes: 1

Views: 62

Answers (2)

invisal
invisal

Reputation: 11171

You can't update the state like this. It is like infinite loop. setState will trigger render, then render will trigger another setState, then you keep repeat the circle.

I don't know why you need isEmpty when you already have toolsUsed which you can use it to check if all input are empty.

Lets say if you insist to have isEmpty, then you can set it inside input change event.

The code is not tesed. I wrote the code directly from browser. But you can get the idea before the code.

renderToolsUsed = () => {
  const { toolsUsed } = this.state;
  const tools = toolsUsed.map((item, i) => {
    return (
      <View key={i} style={styles.tools}>
         <TextInput value={item.name} onChangeText={(text) => {
             this.setState({
                toolsUsed: [
                  ...toolsUsed.slice(0, i - 1),
                  {...item, name: text },
                  ...toolsUSed.slice(i)
                ]
             }, this.updateEmptyState)
         }>
         // other input here
      </View>
    );
 });

 // ...
};

updateEmptyState = () => {
  this.setState({
    isEmpty: this.state.toolsUsed.every(x => x.name === '' && x.price === '' && x.count === '')
  })
}

Upvotes: 3

Yoel
Yoel

Reputation: 7965

The state is not designed to store all the data you have in the app

For what you need isEmpty inside the state?

To do this, use a global variable

Or check it out when you want it out of the render

Upvotes: 0

Related Questions