wyc
wyc

Reputation: 55263

How to fix the following "Too many re-renders error" in React?

I'm trying to render the string array keys into a React component. keys are the keys that the user presses (but I just hard-coded them for the sake of this example).

import { useState } from "react";
import * as ReactDOM from "react-dom";

let keys = ["a", "b"];

function App() {
  let [keysState, setKeysState] = useState([]);

  setKeysState((keysState = keys));

  return (
    <div>
      {keysState.map((key) => (
        <li>{key}</li>
      ))}{" "}
    </div>
  );
}

const rootElement = document.getElementById("root");

ReactDOM.createRoot(rootElement).render(<App />);

But I'm getting this error:

Too many re-renders. React limits the number of renders to prevent an infinite loop.

I know I can avoid this error by creating and onClick handler ... but I don't want to display keysState on click. I want it to display and re-render immediately when keys changes.

Live code: https://codesandbox.io/s/react-18-with-createroot-forked-vgkeiu?file=/src/index.js:0-504

Upvotes: 1

Views: 2251

Answers (4)

monim
monim

Reputation: 4383

when the page loads, the setKeysState function gets invoked and it updates the state, updating the state in reactjs causes a re-render and it keeps doing that infinitely. which produces Too many re-renders error.

just pass an initial value to the useState() hook to initialize the state. like this :

let [keysState, setKeysState] = useState(keys);

NOTE : In your case You do not need The React useState Hook because you're not tracking the data (keys in your case, you are not be updating it ) just change your component like this :

let keys = ["a", "b"];

function App() {

  return (
    <div>
      {keys?.map((key) => (
        <li>{key}</li>
      ))}
    </div>
  );
}

Upvotes: 3

Ovidiu Cristescu
Ovidiu Cristescu

Reputation: 1043

While @monim's answer is great, I feel that you don't need a useState hook if you don't need setKeysState

import * as ReactDOM from "react-dom";

let keys = ["a", "b"];

function App() {

  return (
    <div>
      {keys.map((key) => (
        <li>{key}</li>
      ))}
    </div>
  );
}

const rootElement = document.getElementById("root");

ReactDOM.createRoot(rootElement).render(<App />);

EDIT: I put together a series of links that I did not want to lose. If you want to deep dive, here's what I personally saved on the hooks: https://github.com/criszz77/react-js-links#hooks

Upvotes: 2

MalwareMoon
MalwareMoon

Reputation: 886

There seems to be a bit of confusion as to how useState works. You are getting infinite refreshes, because the component re-renders if there is a change to a state. And what is happening there is, that you component loads, you init your state and set value, which triggers re-render and that runs in loop. To solve it just set initial value to keys instead of []

Things that no one mentioned

  • Make states constants as there is, I think, never a good reason to change the fact that it's a state and if you want to change the value you use setKeysState
  • setKeysState is a function where that you call with the new value of keysState, so do never change value of that state by anything else but setKeysState(newValue). You are passing something that I'd describe as ?function?. Just pass the value.

Solution:

const [keysState, setKeysState] = useState(keys);

Upvotes: 1

Many different problems with this code, and this allow me to tell you that you haven't got the way of React hooks yet.

First of all, you don't need to write this setKeyState function. The useState hook will return it when invoked. enter image description here

Second, if you want to provide an initial value to your keyState, you should do it using the setState hook, just like this:

const [keyState, setKeyState] = useState(["a","b"]);

This would create the keyState variable and initialize it with ["a","b"], as well as provide the setKeyState function.

I believe this is the main problem with this code. This redundance is causing the perpetual re-render.

Finally, you should have some way to react to state changes. This will be given by the useEffect hook.

useEffect(() => {
    // Things to perform when `stateKeys` changes
},[stateKeys])

The second parameter this hook receives [stateKeys] is exactly to prevent a perpetual re-rendering. It tells the hook it should run only when the variables inside this array changes.

It seems to me, allow please don't be offended for me to say, that you missed something in React way of doing things. Specially when it comes to React Hooks. I suggest you to read the documentation again:

https://reactjs.org/docs/hooks-state.html

Upvotes: 0

Related Questions