【问题标题】:React - update state arrayReact - 更新状态数组
【发布时间】:2021-01-14 02:00:21
【问题描述】:

上下文

嗨,

我正在创建一个表单来创建虚拟机。信息跨多个页面(组件)收集并集中在顶级组件中。

它的状态对象如下所示:

const [vmProp, setVmProp] = useState({
    name: "",
    image_id: "",
    image_name: "",
    volumesList: [],
    RAM: "",
    vcpu: "",
    autostart: true,
    });

问题

我希望能够向卷列表添加/删除卷,并且我希望卷列表看起来像这样:

[
    {
      name: "main",
      size: 1024
    },
    {
      name: "backup",
      size: 2048
    },
    {
      name: "export",
      size: 2048
    }
]

我尝试过的

目前我只尝试添加一个卷。

1 : 工作但没有产生我想要的东西

const handleAddVolume = (obj) => {
    setVmProp({ ...vmProp,
        volumesList: {
            ...vmProp.volumesList,
            [obj.name]: {
                size: obj.size,
            },
        } });
};

它正在工作,但输出是:

[
    name: {
      size: 1024
    }
]

2 :应该可以工作,但不是

const handleAddVolume = (obj) => {
    setVmProp({ ...vmProp,
        volumesList: {
            ...vmProp.volumesList,
            {
                name: obj.name,
                size: obj.size,
            },
        } });
};

输出:

[
    name: "main",
    size: 1024

]

您对如何处理此类状态对象有任何想法吗? 谢谢

【问题讨论】:

  • volumesList 成为它自己的状态原子,你会玩得更好。 (最好让所有不同的位成为自己的原子。)

标签: javascript arrays reactjs object react-hooks


【解决方案1】:

如果您不需要从其他状态嵌套/取消嵌套卷列表,您将有更好的时间。 (更惯用的方法是为这些值中的每一个设置一个状态原子,但对于布尔值和字符串等简单值,这将是可行的。)

const [vmProps, setVmProps] = useState({
  name: "",
  image_id: "",
  image_name: "",
  RAM: "",
  vcpu: "",
  autostart: true,
});
const [volumesList, setVolumesList] = useState([]);

【讨论】:

    【解决方案2】:

    volumesList 不应该是对象,在 handleAddVolume 函数中将其作为数组。

    试试下面的方法,

    const handleAddVolume = (obj) => {
        setVmProp({ ...vmProp,
            volumesList: [
                ...vmProp.volumesList,
                {
                    name: obj.name,
                    size: obj.size,
                }
            ] });
    };
    

    【讨论】:

      【解决方案3】:

      这是一个工作示例:

      const Example = (props) => {
        const inputRef = createRef();
        const [vmProp, setVmProp] = useState({
          name: "",
          image_id: "",
          image_name: "",
          volumesList: [],
          RAM: "",
          vcpu: "",
          autostart: true,
        });
      
        const { volumesList } = vmProp;
      
        const handleAddVolume = (e) => {
          e.preventDefault();
          const input = inputRef.current.value;
          setVmProp((prevVmProp) => {
            const newVmProp = { ...prevVmProp };
            newVmProp.volumesList.push({
              name: input,
              size: 1024,
            });
            return newVmProp;
          });
          // reset the input
          inputRef.current.value = "";
        };
      
        return (
          <>
            <form>
              <input ref={inputRef} type="text" />
              <button onClick={handleAddVolume}>Add volume</button>
            </form>
            {volumesList.map((volume) => (
              <div key={volume.name}>{`${volume.name} - ${volume.size}`}</div>
            ))}
          </>
        );
      };
      
      export default Example;
      

      这只是一个概念证明。基本上,setVmProp 接受一个获取最新状态值的函数,因为更新是异步的,并返回状态的新值。所以使用ES6's destructuring函数,我复制了vmProp的最新值newVmProp ,然后将一个新对象推送到newVmProp.volumesList,然后返回包含新添加的卷+其他所有内容的newVmProp。我从输入字段中获得的name 的值。同样,这只是一个概念证明。

      【讨论】:

        【解决方案4】:

        由于我需要能够在我的数组中添加/删除/替换一个对象,我决定创建它自己的状态,如下所示:

        
        const [volumesList, setVolumesList] = useState([]);
        
        const handleAddVolume = (obj) => {
            setVolumesList((oldList) => [...oldList, obj]);
        };
        
        const handleRemoveVolume = (obj) => {
            setVolumesList((oldList) => oldList.filter((item) => item.name !== obj.name));
        };
        
        const handleEditVolume = (obj) => {
            setVolumesList(
                volumesList.map((volume) =>
                    (volume.name === obj.name
                        ? { ...volume, ...obj }
                        : volume),
                ),
            );
        };
        

        感谢您的所有回答!

        【讨论】:

          猜你喜欢
          • 2020-09-06
          • 2020-10-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多