简体   繁体   中英

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

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

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

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

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. 在此处输入图像描述

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM