【问题标题】:React hooks useState ArrayReact 钩子 useState 数组
【发布时间】:2023-03-19 20:34:01
【问题描述】:

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

尝试将下拉值从初始状态更改为 allowedState 值。我在这里使用钩子方法来设置使用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);

【问题讨论】:

  • 您实际上是在设置导致重新渲染的状态,设置状态,重新渲染等。

标签: reactjs react-hooks


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    尽量保持你的状态最小。无需存储

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

    【讨论】:

    • 这在功能上是不等价的,它会在每个后续菜单打开时显示-- Select a State --,而最初的实现只显示它。
    • @AvinKavish,我不明白你的意思。查看 Ryan 的演示,“--- Select a State ---”根本不显示,可以省略。你能解释一下你的意思吗?
    • 哦,是的,我只是假设因为它被称为初始值,所以它的行为是这样的。我的答案显示了一个实现,其中 select a state 最初显示但消失并且无法重新选择。
    • @AvinKavish,很酷。顺便说一句,您似乎收到了有关我的新答案的通知。怎么会?我也想使用这个解决方案。
    【解决方案3】:

    接受的答案显示了 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);
    

    【讨论】:

      【解决方案4】:

      扩展 Ryan 的回答:

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

      反应docs:

      setState() 总是会导致重新渲染,除非 shouldComponentUpdate() 返回 false。

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

      setStateValues(allowedState);
      

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

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

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

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

      在您的情况下,您正在处理一个副作用,该副作用由您的组件函数中的 UseEffect 处理。你可以阅读更多关于它的信息here。

      【讨论】:

        【解决方案5】:

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

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

        然后在像这样的地图循环中使用您的数据,在我的情况下,它只是一个表格,我相信你们中的许多人都在寻找相同的东西。这是你如何使用它。

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

        【讨论】:

          【解决方案6】:
          //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)
                  })
               
              }
          

          【讨论】:

            猜你喜欢
            • 2020-11-02
            • 2021-04-04
            • 2021-02-07
            • 1970-01-01
            • 2021-04-04
            • 2021-05-25
            • 2020-04-29
            • 1970-01-01
            • 2023-01-04
            相关资源
            最近更新 更多