React 钩子 useState Array

IT技术 reactjs react-hooks
2021-05-22 00:02:07

我尝试useState在这里寻找重置数组值,但找不到任何对数组值的引用。

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

我收到以下错误:

太多的重新渲染。React 限制渲染次数以防止无限循环

这里有什么问题吗?

    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);
4个回答

你不应该在渲染函数中设置状态(或做任何其他有副作用的事情)。使用钩子时,您可以使用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);

这里是一个代码沙箱

我假设您希望最终从某个动态源加载状态列表(否则您可以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 的正确方法,但它不会导致功能良好的选择框。

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

扩展瑞安的回答:

每当 setStateValues 被调用时,React 都会重新渲染你的组件,这意味着StateSelector组件函数的函数体被重新执行。

react文档

setState() 将始终导致重新渲染,除非 shouldComponentUpdate() 返回 false。

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

setStateValues(allowedState);

导致重新渲染,然后导致函数执行,依此类推。因此,循环问题。

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

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

这结束了“太多重新渲染”的问题。

在您的情况下,您正在处理副作用,这是UseEffect在您的组件函数中处理的您可以在此处阅读更多相关信息