简体   繁体   English

将对象附加到数组,为什么“推送”不起作用?

[英]Append an object to an array, why does "push" not work?

I just want to understand why line 33 does not work (marked out), but line 32 does work.我只是想知道为什么线33不起作用(标注出来),但32行确实工作。 Why am I unable to simply push an object to the array?为什么我不能简单地将对象推送到数组? Shouldn't these two lines (line 32 and 33) do the exact same thing?这两行(第 32 行和第 33 行)不应该做完全相同的事情吗?

Reference: https://codesandbox.io/s/lingering-wood-33vtb?file=/src/App.js:0-927参考: https : //codesandbox.io/s/lingering-wood-33vtb?file=/src/ App.js: 0-927

import React, { useState } from "react";

function ThingsToDo({ thing }) {
  return <div>{thing.text}</div>;
}

function ToDoForm({ add }) {
  const [value, setValue] = useState("");

  const updateKey = (e) => {
    e.preventDefault();
    if (!value) return;
    add(value);
    setValue("");
  };

  return (
    <form onSubmit={updateKey}>
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
    </form>
  );
}

function App() {
  const [todos, setTodos] = useState([{ text: "Hi" }, { text: "Bye" }]);

  const Addtolist = (text) => {
    const newToDo = [...todos, { text }];
    //     const newToDo = todos.push({text})
    setTodos(newToDo);
  };

  return (
    <div>
      {todos.map((todo, index) => (
        <div>
          <ThingsToDo thing={todo} />
        </div>
      ))}
      <ToDoForm add={Addtolist} />
    </div>
  );
}

export default App;

You can't mutate a state directly in react.你不能在反应中直接改变状态。 In your 2 cases:在您的两种情况下:

    const newToDo = [...todos, { text }];

This one creates a copy of the todos array and adds your extra item.这将创建 todos 数组的副本并添加您的额外项目。 newTodo is a copy and then when you setTodos(newTodo) you set the state to the new copied array. newTodo 是一个副本,然后当您 setTodos(newTodo) 时,您将状态设置为新复制的数组。

 const newToDo = todos.push({text})

This one tries to push {text} into todos which is a state.这个试图将 {text} 推入 todos 这是一种状态。 You can't mutate a state directly you have to do this through setTodos().你不能直接改变状态,你必须通过 setTodos() 来做到这一点。

If you are really set on using push then you can copy the state of todos first then push into the copied array but I think this is extra unecessary work.如果你真的开始使用推送,那么你可以先复制 todos 的状态,然后推送到复制的数组中,但我认为这是额外的不必要的工作。

You have to do as following,你必须做如下,

// const newToDo = [...todos, { text }];
const newToDo = JSON.parse(JSON.stringify(todos));
newToDo.push({ text });
setTodos(newToDo);

Reasons:原因:

  1. You are attempting to mutate the state variable todos (will not work), you have to use setState您正在尝试改变状态变量 todos(不起作用),您必须使用 setState
  2. If you really want to mutate and set new state, you have to clone using JSON.parse, JSON.strigify, you can't create a real clone otherwise如果你真的想改变并设置新的状态,你必须使用 JSON.parse, JSON.strigify 进行克隆,否则你无法创建真正的克隆

As official React document https://reactjs.org/docs/react-component.html says,正如官方 React 文档https://reactjs.org/docs/react-component.html所说,

NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made.永远不要直接改变 this.state,因为之后调用 setState() 可能会替换你所做的改变。 Treat this.state as if it were immutable.将 this.state 视为不可变的。

You are trying to push an object inside React state array which violates the immutability.您试图将一个对象推送到 React 状态数组中,这违反了不变性。 To update the react state, you will definitely have to use setState (in your case setTodos since you are building functional component).要更新反应状态,您肯定必须使用setState (在您的情况下是setTodos因为您正在构建功能组件)。

And another thing is when you push the array and assign it to a const variable, it will assign the length of the array instead of the array which is what you wanted.另一件事是,当您推送数组并将其分配给 const 变量时,它将分配数组的长度而不是您想要的数组。

As w3school page says in https://www.w3schools.com/jsref/jsref_push.asp正如 w3school 页面在https://www.w3schools.com/jsref/jsref_push.asp 中所说

The push() method adds new items to the end of an array, and returns the new length. push() 方法将新项添加到数组的末尾,并返回新长度。

My alternative to solving this problem is to use .concat method of Array type because it will not mutate the original array but it will just return a new array with concatted objects instead.我解决这个问题的替代方法是使用Array类型的.concat方法,因为它不会改变原始数组,而只会返回一个带有连接对象的新数组。

Example.例子。

setTodos(todos.concat(text));

Ref:参考:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

1st case第一种情况

That is not going to work.那是行不通的。 To trigger the state change you must use the setState to update the state.要触发状态更改,您必须使用setState来更新状态。 With the todo.push({ text }) it will update the state but never going to trigger the state changes.使用todo.push({ text })它将更新状态但永远不会触发状态更改。

2nd case第二种情况

push returns the item you added to the array. push返回您添加到数组中的项目。 So in setState you are try to override the current state array with { text : "somText" } .因此,在 setState 中,您尝试使用{ text : "somText" }覆盖当前状态数组。 So now in your render method you can't map through the state array & you are getting an Error.所以现在在你的渲染方法中你不能通过状态数组进行映射,你会得到一个错误。

3rd case第三种情况

You need to understand that arrays are reference type.您需要了解数组是引用类型。 So even you did something like below, it is directly update the todo array since this is not a real copy.所以即使你做了类似下面的事情,它也会直接更新 todo 数组,因为这不是一个真正的副本。

let copy = todo;
copy.push({text});
setTodo(copy)

There are two ways that you can copy.有两种方法可以复制。

  1. Shallow Copy浅拷贝
  2. Deep Copy深拷贝

In Shallow Copy you only copies the values and the prototype will still refer to the original object.在浅拷贝中,您只复制值,原型仍将引用原始对象。

In deep copy it copies everything.在深度复制中,它复制所有内容。 Even the references are copied.甚至参考文献也被复制。

In your case shallow copy is enough for perform the state update.在您的情况下,浅拷贝足以执行状态更新。 You can do the shallow copy by [...todos, {text}]你可以通过[...todos, {text}]做浅拷贝

In JavaScript if you need to do a deep copy, an easy way to do is,在 JavaScript 中,如果您需要进行深度复制,一个简单的方法是,

const deepCpy = JSON.parse(JSON.stringiy(todos))

Also you can use deepCopy method in lodash您也可以在lodash使用 deepCopy 方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果 useState 的值是 object 而不是数组,为什么 reverse() 会起作用? - Why does reverse() work if the value of useState is an object and not if it is an array? 为什么 slice push 在 redux 中有效,但在 concat 中无效? - Why does slice push work in redux but not concat? 为什么它不将元素推入数组 state“任务”? - Why does it not push the element into the array state "tasks"? 循环遍历两个对象数组以将匹配值推入新数组在React中不起作用,但在JS Fiddle中起作用 - Looping through two object arrays to push matching values to a new array doesn't work in React but does in JS Fiddle 为什么我无法将 object 推送到我的阵列现有阵列? - Why I cant push an object to my array existing array? 将 object 的数组推送到数组 - Push array of an object to array 为什么我的 history.push 在一个 function 中起作用,而在另一个中起作用? - Why does my history.push work in one function but the other? 为什么处于反应状态的数组的pop()或push()方法可以工作 - Why the pop() or push() method of an array in the state of react can work React Native setState 不会使 array.push 工作 - React Native setState does not make array.push work .push()在构造函数中不起作用? - .push() does not work in the constructor?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM