【问题标题】:Push method in React Hooks (useState)?React Hooks(useState)中的推送方法?
【发布时间】:2019-07-07 16:28:54
【问题描述】:

如何在 useState 数组 React 钩子中推送元素? 这是反应状态下的旧方法吗?还是新的东西?

例如setState push example?

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    当你使用useState时,你可以获得状态项的更新方法:

    const [theArray, setTheArray] = useState(initialArray);
    

    然后,当您想要添加新元素时,您可以使用该函数并传入新数组或将创建新数组的函数。通常是后者,因为状态更新是异步的,有时是批处理的:

    setTheArray(oldArray => [...oldArray, newElement]);
    

    如果您为某些特定的用户事件(如click(但不像mousemove)更新处理程序中的数组,则有时您可以不使用该回调表单而侥幸逃脱:

    setTheArray([...theArray, newElement]);
    

    React 确保刷新渲染的事件是here 列出的“离散事件”。

    实时示例(将回调传递给setTheArray):

    const {useState, useCallback} = React;
    function Example() {
        const [theArray, setTheArray] = useState([]);
        const addEntryClick = () => {
            setTheArray(oldArray => [...oldArray, `Entry ${oldArray.length}`]);
        };
        return [
            <input type="button" onClick={addEntryClick} value="Add" />,
            <div>{theArray.map(entry =>
              <div>{entry}</div>
            )}
            </div>
        ];
    }
    
    ReactDOM.render(
        <Example />,
        document.getElementById("root")
    );
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>

    因为对theArray 的唯一更新是click 事件(“离散”事件之一)中的一个,所以我可以直接更新addEntry

    const {useState, useCallback} = React;
    function Example() {
        const [theArray, setTheArray] = useState([]);
        const addEntryClick = () => {
            setTheArray([...theArray, `Entry ${theArray.length}`]);
        };
        return [
            <input type="button" onClick={addEntryClick} value="Add" />,
            <div>{theArray.map(entry =>
              <div>{entry}</div>
            )}
            </div>
        ];
    }
    
    ReactDOM.render(
        <Example />,
        document.getElementById("root")
    );
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>

    【讨论】:

    • ...如果上述方法不起作用,请尝试setTheArray(currentArray =&gt; [...currentArray, newElement])。最有可能在useEffect(...theArray..., []) 中,重要的是要意识到theArray 是一个常量,因此未来渲染的值需要functional updates
    • @Aprillion - 不太清楚你在说什么 useEffect 例子...?
    • 如果useEffect有一个空的依赖列表[],它只会在第一次渲染时执行。所以效果中theArray的值永远是initialArray。在setTheArray([...initialArray, newElement]) 没有意义的情况下,并且当theArray 常量将始终等于initialValue 时,则需要进行功能更新。
    • @Aprillion - 恐怕我还是听不懂,可能有点密集。 :-) 为什么只需要 initial 数组值的效果? (我的意思是,可能有一个不常见的用例,但是......)即使你这样做了,它与问题有什么关系?
    • 嘿@TJCrowder,我在获取数据时使用回调方式将旧数据与新数据合并,但由于某种原因它不能正常工作,请您查看this以了解我的问题?
    【解决方案2】:

    为了进一步扩展, 这里有一些常见的例子。开始于:

    const [theArray, setTheArray] = useState(initialArray);
    const [theObject, setTheObject] = useState(initialObject);
    

    将元素推入数组末尾

    setTheArray(prevArray => [...prevArray, newValue])
    

    在对象末尾推送/更新元素

    setTheObject(prevState => ({ ...prevState, currentOrNewKey: newValue}));
    

    在对象数组的末尾推送/更新元素

    setTheArray(prevState => [...prevState, {currentOrNewKey: newValue}]);
    

    将元素推入数组对象的末尾

    let specificArrayInObject = theObject.array.slice();
    specificArrayInObject.push(newValue);
    const newObj = { ...theObject, [event.target.name]: specificArrayInObject };
    theObject(newObj);
    

    这里还有一些工作示例。 https://codesandbox.io/s/reacthooks-push-r991u

    【讨论】:

    • 感谢您提供的所有示例。我遇到的确切问题是您的 Push 元素位于数组对象的末尾。我尝试了很多不同的东西,但就是无法拼凑起来。
    • prevState 的使用解决了我的问题,即只有最后一个调用应用于同时数组 concat 和过滤器。
    【解决方案3】:

    您可以在自定义状态的末尾附加数据数组:

      const [vehicleData, setVehicleData] = React.useState<any[]>([]);
      setVehicleData(old => [...old, ...newArrayData]);
    

    例如,在下面,你出现了一个 axios 的例子:

      useEffect(() => {
        const fetchData = async () => {
          const result = await axios(
            {
              url: `http://localhost:4000/api/vehicle?page=${page + 1}&pageSize=10`,
              method: 'get',
            }
          );
          setVehicleData(old => [...old, ...result.data.data]);
        };
    
        fetchData();
      }, [page]);
    

    【讨论】:

      【解决方案4】:

      最推荐的方法是同时使用包装函数和展开运算符。例如,如果您像这样初始化了一个名为name 的状态,

      const [names, setNames] = useState([])

      你可以像这样推送到这个数组,

      setNames(names => [...names, newName])
      

      希望对您有所帮助。

      【讨论】:

      • 请不要发布仅链接的答案。该链接将来可能会断开。相反,请撰写该文章的文章,并确保实际回答问题。
      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
      【解决方案5】:

      与 React 类组件中的“正常”状态相同。

      示例:

      function App() {
        const [state, setState] = useState([]);
      
        return (
          <div>
            <p>You clicked {state.join(" and ")}</p>
            //destructuring
            <button onClick={() => setState([...state, "again"])}>Click me</button>
            //old way
            <button onClick={() => setState(state.concat("again"))}>Click me</button>
          </div>
        );
      }
      

      【讨论】:

      • 这将与 onClick 一起使用,但 setState(oldState => [...oldState, pushsomething]) 是你应该这样做的方式
      【解决方案6】:
      // Save search term state to React Hooks with spread operator and wrapper function
      
      // Using .concat(), no wrapper function (not recommended)
      setSearches(searches.concat(query))
      
      // Using .concat(), wrapper function (recommended)
      setSearches(searches => searches.concat(query))
      
      // Spread operator, no wrapper function (not recommended)
      setSearches([...searches, query])
      
      // Spread operator, wrapper function (recommended)
      setSearches(searches => [...searches, query])
      

      https://medium.com/javascript-in-plain-english/how-to-add-to-an-array-in-react-state-3d08ddb2e1dc

      【讨论】:

        【解决方案7】:

        使用 useState() 创建一个数组状态 首先,让我们看看如何使用 useState() 钩子来创建数组状态变量。

        import React from "react";
        
        const { useState } = React;
        
        const [myArray, setMyArray] = useState([]);
        

        但是,在 React 中,我们需要使用从 useState 返回的方法来更新数组。

        setMyArray(oldArray => [...oldArray, newElement]);
        

        know more

        【讨论】:

        • '(oldArray: { array1: string[]; }) => any[]' 类型的参数不可分配给'SetStateAction'。类型 '(oldArray: { array1: string[]; }) => any[]' 不可分配给类型 '(prevState: { array1: string[]; }) => { array1: string[]; }'。类型“any[]”中缺少属性“array1”,但类型“{ array1: string[]; }'.ts(2345)
        【解决方案8】:

        setTheArray([...theArray, newElement]); 是最简单的答案,但要注意 theArray 中项目的变异。使用数组项的深度克隆。

        【讨论】:

        【解决方案9】:

        我尝试了上述方法将对象推送到 useState 中的对象数组中,但在使用 TypeScript 时出现以下错误:

        键入'TxBacklog[] | undefined' 必须有一个返回 iterator.ts(2488) 的 'Symbol.iterator' 方法

        tsconfig.json 的设置显然是正确的:

        {
           "compilerOptions": {
           "target": "es6",
           "lib": [
              "dom",
              "dom.iterable",
              "esnext",
              "es6",
        ],
        

        此解决方法解决了问题(我的示例代码):

        界面:

           interface TxBacklog {
              status: string,
              txHash: string,
           }
        

        状态变量:

            const [txBacklog, setTxBacklog] = React.useState<TxBacklog[]>();
        

        将新对象推入数组:

            // Define new object to be added
            const newTx = {
               txHash: '0x368eb7269eb88ba86..',
               status: 'pending'
            };
            // Push new object into array
            (txBacklog) 
               ? setTxBacklog(prevState => [ ...prevState!, newTx ])
               : setTxBacklog([newTx]);
        

        【讨论】:

          【解决方案10】:

          如果您想在特定索引之后推送,您可以执行以下操作:

             const handleAddAfterIndex = index => {
                 setTheArray(oldItems => {
                      const copyItems = [...oldItems];
                      const finalItems = [];
                      for (let i = 0; i < copyItems.length; i += 1) {
                          if (i === index) {
                              finalItems.push(copyItems[i]);
                              finalItems.push(newItem);
                          } else {
                              finalItems.push(copyItems[i]);
                          }
                      }
                      return finalItems;
                  });
              };
          

          【讨论】:

            猜你喜欢
            • 2019-06-06
            • 1970-01-01
            • 1970-01-01
            • 2022-07-09
            • 2020-12-28
            • 2020-04-13
            • 2020-03-23
            相关资源
            最近更新 更多