React hooks useState 数组

React hooks useState Array

我尝试在此处查找重置 useState 数组值,但找不到任何对数组值的引用。

正在尝试将下拉值从初始状态更改为 allowedState 值。我在这里使用钩子方法来设置使用 setStateValues 的值。如果我评论那行代码,它会显示下拉列表。我不明白为什么我不能使用 setStateValues 方法来重置状态变量值。

我收到以下错误:

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

这里有什么问题吗?

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

你不应该在渲染函数中设置状态(或做任何其他有副作用的事情)。使用钩子时,可以使用useEffect

以下版本有效:

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

here it is in a code sandbox.

我假设您想最终从某个动态源加载状态列表(否则您可以直接使用 allowedState 而根本不使用 useState)。如果是这样,加载列表的 api 调用也可以进入 useEffect 块。

尽量保持最小状态。不需要存储

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

作为状态。将永久与变化分开

const ALL_STATE_VALS = [
    { id: 0,value: " --- Select a State ---" }
    { id: 1, value: "Alabama" },
    { id: 2, value: "Georgia" },
    { id: 3, value: "Tennessee" }
];

然后你可以只存储 id 作为你的状态:

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

接受的答案显示了 setState 的正确方法,但它不会导致功能良好的 select 框。

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

扩展 Ryan 的回答:

每当调用 setStateValues 时,React re-renders 你的组件,这意味着 StateSelector 组件函数的函数体得到 re-executed。

反应 docs:

setState() will always lead to a re-render unless shouldComponentUpdate() returns false.

本质上,您正在设置状态:

setStateValues(allowedState);

导致 re-render,然后导致函数执行,依此类推。因此,循环问题。

为了说明这一点,如果您将超时设置为:

  setTimeout(
    () => setStateValues(allowedState),
    1000
  )

'too many re-renders' 问题到此结束。

在您的例子中,您正在处理一个 side-effect,它在您的组件函数中由 UseEffect 处理。您可以阅读更多相关信息 here

并不总是需要使用状态你可以简单地这样做

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

然后在像这样的地图循环中使用您的数据,在我的例子中它只是一个 table,我相信你们中的许多人都在寻找相同的数据。这是你如何使用它。

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