1

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

6
  • 1
    I think you are missing something about useState. You don't need to write this setKeyState function. It is already returned by useState, based on de type of the inicial value provided. Commented Nov 27, 2022 at 11:54
  • 1
    Please read the documentation again: reactjs.org/docs/hooks-state.html Commented Nov 27, 2022 at 11:56
  • @EddeAlmeida You mean I should just do useState(keys) and not use setKeysState? I'm not very sure what you mean. Commented Nov 27, 2022 at 12:35
  • 1
    No @alexchenco. What I mean is you don't need to write this setKeyState function, since it is already provided by the useState hook. Commented Nov 27, 2022 at 12:37
  • 3
    This syntax makes absolutely no sense : setKeysState((keysState = keys)); Commented Nov 27, 2022 at 13:00

4 Answers 4

4

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> ); } 
Sign up to request clarification or add additional context in comments.

3 Comments

This being the most upvoted answer you need to point out that he should remove the part of the code where he calls setKeysState whenever his App component renders because of the things you already mentioned. Otherwise, modifying initial state value in his current setup won't simply avoid his infinite re-renders.
Yeah got it I didn't mention it I'll update my answer
Thanks for the answer. I just realized keysState only runs once. If keys is updated, keysState doesn't change.
2

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

4 Comments

You have somewhat correct answer in here, your code unlike the answer you mentioned, and currently most upvoted one, at least shows a code that would not cause infinite re-renders, but OP didn't showed a code where his his keys state would come from props, so in your case example keys would equal to undefined. But you are right that he doesn't need a setter function if he isn't updating the keys state.
His question mentioned that he hardcoded the keys. So I assumed he would receive that by props. But you are right, I could be more clear. Let me update my post.
You mean if I want to use your code I have to do this? function App(keys) { ... } Use keys as a React prop?
No, I believed that’s your real case, where you receive the keys by props from a parent component, but not by hardcoding them. My answer is updated with your hardcoded keys now.
1

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

Comments

0

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

1 Comment

@EddeAlmeida I haven't upvoted nor downvoted any answer but yours seem to be on point, yet it's weird how you got 3 comment upvotes but none of them upvoted your answer. The only thing I would like to mention is that "you don't need to write this setKeyState function" - I'm not sure whether the downvoter thought of it as "you don't need to destructure the setter function from useState's returned value", or whatever, however later on you showed a correct example and on top of it an extra information. Bcuz he never overrides setKeyState his mistake instead is calling setKeyState on renders.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.