I tried looking for resetting useState array values in here but could not find any references to array values.
Trying to change the drop down value from initial state to allowedState values. I am using hooks method here to set the values using setStateValues. If I comment that line of code, it displays the drop down. I could not understand why cannot I use setStateValues method to reset the state variable values.
I am getting this following error:
Too many re-renders. React limits the number of renders to prevent an infinite loop
Is there something wrong in here?
import React, { useState } from "react";
import ReactDOM from "react-dom";
const StateSelector = () => {
const initialValue = [
{ id: 0,value: " --- Select a State ---" }];
const allowedState = [
{ id: 1, value: "Alabama" },
{ id: 2, value: "Georgia" },
{ id: 3, value: "Tennessee" }
];
const [stateOptions, setStateValues] = useState(initialValue);
// initialValue.push(...allowedState);
console.log(initialValue.length);
setStateValues(allowedState); // Not sure why cannot I reset the state in here for an array.
return (<div>
<label>Select a State:</label>
<select>
{stateOptions.map((localState, index) => (
<option key={localState.id}>{localState.value}</option>
))}
</select>
</div> ); };
const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);
You should not set state (or do anything else with side effects) from within the rendering function. When using hooks, you can use useEffect for this.
The following version works:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const StateSelector = () => {
const initialValue = [
{ id: 0, value: " --- Select a State ---" }];
const allowedState = [
{ id: 1, value: "Alabama" },
{ id: 2, value: "Georgia" },
{ id: 3, value: "Tennessee" }
];
const [stateOptions, setStateValues] = useState(initialValue);
// initialValue.push(...allowedState);
console.log(initialValue.length);
// ****** BEGINNING OF CHANGE ******
useEffect(() => {
// Should not ever set state during rendering, so do this in useEffect instead.
setStateValues(allowedState);
}, []);
// ****** END OF CHANGE ******
return (<div>
<label>Select a State:</label>
<select>
{stateOptions.map((localState, index) => (
<option key={localState.id}>{localState.value}</option>
))}
</select>
</div>);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);
and here it is in a code sandbox.
I'm assuming that you want to eventually load the list of states from some dynamic source (otherwise you could just use allowedState directly without using useState at all). If so, that api call to load the list could also go inside the useEffect block.
Try to keep your state minimal. There is no need to store
const initialValue = [
{ id: 0,value: " --- Select a State ---" }];
as state. Separate the permanent from the changing
const ALL_STATE_VALS = [
{ id: 0,value: " --- Select a State ---" }
{ id: 1, value: "Alabama" },
{ id: 2, value: "Georgia" },
{ id: 3, value: "Tennessee" }
];
Then you can store just the id as your state:
const StateSelector = () =>{
const [selectedStateOption, setselectedStateOption] = useState(0);
return (
<div>
<label>Select a State:</label>
<select>
{ALL_STATE_VALS.map((option, index) => (
<option key={option.id} selected={index===selectedStateOption}>{option.value}</option>
))}
</select>
</div>);
)
}
To expand on Ryan's answer:
Whenever setStateValues is called, React re-renders your component, which means that the function body of the StateSelector component function gets re-executed.
React docs:
setState() will always lead to a re-render unless shouldComponentUpdate() returns false.
Essentially, you're setting state with:
setStateValues(allowedState);
causing a re-render, which then causes the function to execute, and so on. Hence, the loop issue.
To illustrate the point, if you set a timeout as like:
setTimeout(
() => setStateValues(allowedState),
1000
)
Which ends the 'too many re-renders' issue.
In your case, you're dealing with a side-effect, which is handled with UseEffectin your component functions. You can read more about it here.