Logan Lee
Logan Lee

Reputation: 987

Calling set function of useState causes infinite loop

import React from 'react';
import Test from './Test';

function App() {
  return (
    <Test />
  );
}

export default App;

import React, { useState } from "react";

const Test = () => {
  const [stuff, setStuff] = useState({ a: "alpha", b: "alpha" });

  setStuff({                // this causes infinite loop!
    ...stuff,               // removing setStuff() fixes it.
    a: "omega"
  });

  return <p>{JSON.stringify(stuff)}</p>;
};

export default Test;

I'm using useState() inside Test.js and setStuff() causes infinite loop.

Can someone explain why? And how to fix it (if I want to call setStuff to update stuff)?

Here's working codesandbox: https://codesandbox.io/s/loving-jennings-pr3nl

Upvotes: 1

Views: 271

Answers (2)

Doppio
Doppio

Reputation: 2188

The simple rule is "don't setState in render function", because setState will trigger a render function, and if in render function, you setState, then it goes on and on and on.

You should bind "setState" to an event, like a mouse click, a keyboard press, or component finish loading event, and setState in that event.... but never never in render function.

In Class Component

import React from 'react'
class Test extends React.Component {
  render() {
    // Don't setState here.
    return (<div>test</div>)
  }
} 

In functional Component

const Test = () => {
  // Don't setState here.
  return (<div>test</div>)
} 

** Update

Example of how to use setState

In Class Component

import React from 'react'
class Test extends React.Component {
  state = {
    value: 4
  }

  handleClickAdd = (e) => {
    const currentValue = this.state.value; 
    this.setState({ value: currentValue + 1 }); // set currentValue + 1 as a new state value.
  }

  render() {
    // Don't setState here.
    return (
      <div>
        test {this.state.value}
        <button onClick={this.handleClickAdd}>Add</button>
      </div>
    )
  }
} 

In functional Component

const Test = () => {

  const [value, setValue] = useState(4);

  const handleClickAdd = e => {
    setValue(value + 1);
  }

  // Don't setState here.
  return (
    <div>
      test {value}
      <button onClick={handleClickAdd}>Add</button>
    </div>
  )
} 

Upvotes: 1

Logan Lee
Logan Lee

Reputation: 987

This works

const doStuff=()=>{
    setStuff({
      ...stuff,
      a: "omega"
    });
  };

  useEffect(doStuff,[]);

Expected output:

{"a":"omega","b":"alpha"}

Upvotes: 0

Related Questions