React hooks useState Array

ReactjsReact Hooks

Reactjs Problem Overview


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

Reactjs Solutions


Solution 1 - Reactjs

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.

Solution 2 - Reactjs

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

Solution 3 - Reactjs

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.

Solution 4 - Reactjs

The accepted answer shows the correct way to setState but it does not lead to a well functioning select box.

import React, { useState } from "react"; 
import ReactDOM from "react-dom";

const initialValue = { id: 0,value: " --- Select a State ---" };

const options = [
    { id: 1, value: "Alabama" },
    { id: 2, value: "Georgia" },
    { id: 3, value: "Tennessee" }
];

const StateSelector = () => {   
   const [ selected, setSelected ] = useState(initialValue);  

     return (
       <div>
          <label>Select a State:</label>
          <select value={selected}>
            {selected === initialValue && 
                <option disabled value={initialValue}>{initialValue.value}</option>}
            {options.map((localState, index) => (
               <option key={localState.id} value={localState}>
                   {localState.value}
               </option>
             ))}
          </select>
        </div>
      ); 
};

const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);

Solution 5 - Reactjs

use state is not always needed you can just simply do this

let paymentList = [
    {"id":249,"txnid":"2","fname":"Rigoberto"}, {"id":249,"txnid":"33","fname":"manuel"},]

then use your data in a map loop like this in my case it was just a table and im sure many of you are looking for the same. here is how you use it.

<div className="card-body">
            <div className="table-responsive">
                <table className="table table-striped">
                    <thead>
                        <tr>
                            <th>Transaction ID</th>
                            <th>Name</th>
                        </tr>
                    </thead>
                    <tbody>
                        {
                            paymentList.map((payment, key) => (
                                <tr key={key}>
                                    <td>{payment.txnid}</td>
                                    <td>{payment.fname}</td>
                                </tr>
                            ))
                        }
                    </tbody>
                </table>
            </div>
        </div>

Solution 6 - Reactjs

//get value
 const valor1 = event.target.elements.valor1.value;
//add to value object
        const todo = {
            valor1,
        }
//push to new value or your state
        setValor(prevLista =>{
            return prevLista.concat(todo)
        })
     
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionshaviView Question on Stackoverflow
Solution 1 - ReactjsRyan CogswellView Answer on Stackoverflow
Solution 2 - ReactjsBen CarpView Answer on Stackoverflow
Solution 3 - ReactjsJoel HView Answer on Stackoverflow
Solution 4 - ReactjsAvin KavishView Answer on Stackoverflow
Solution 5 - ReactjsjerryurenaaView Answer on Stackoverflow
Solution 6 - ReactjsFernando AlcantaraView Answer on Stackoverflow