reactjs 如何更新动态多输入(用户可以自己添加这些输入)?

7vhp5slm  于 2022-12-29  发布在  React
关注(0)|答案(1)|浏览(177)

我有一个表单。最初有一些默认值(用户名和地址)。当用户点击add时,有一个额外的输入,用户可以输入另一个名称和地址,额外的名称和地址将存储在additionConfigs中。
示例:https://codesandbox.io/s/elastic-pateu-2uy4rt

import "./styles.css";
import { useState, useEffect } from "react";

export default function App() {
  const [value, setValue] = useState([]);
  const [additionConfigs, setAdditionConfigs] = useState([]);
  useEffect(() => {
    setTimeout(() => {
      setValue([
        {
          id: 1,
          baseName: "XXX",
          config: {
            name: "Kenny",
            address: "New york"
          }
        },
        {
          id: 2,
          baseName: "YYY",
          config: {
            name: "Ben",
            address: "Boston"
          }
        },
        {
          id: 3,
          baseName: "ZZZ",
          config: {
            name: "Mary",
            address: "Los Angeles"
          }
        }
      ]);
    }, 1000);
  }, []);
  const onAddBaseConfig = (item) => {
    setAdditionConfigs((preValue) => [
      ...preValue,
      {
        id: item.id,
        config: {
          name: "",
          address: ""
        }
      }
    ]);
  };
  console.log(additionConfigs);
  const onChangeName = (e, id) => {
    setAdditionConfigs((preValue) => {
      const newValue = preValue.map((v) => {
        if (v.id === id) {
          return {
            ...v,
            config: {
              ...v.config,
              name: e.target.value
            }
          };
        }
        return v;
      });
      return newValue;
    });
  };
  const onChangeAddress = (e, id) => {
    setAdditionConfigs((preValue) => {
      const newValue = preValue.map((v) => {
        if (v.id === id) {
          return {
            ...v,
            config: {
              ...v.config,
              address: e.target.value
            }
          };
        }
        return v;
      });
      return newValue;
    });
  };
  return (
    <>
      {value.length > 0 &&
        value.map((v, index) => (
          <div className="item" key={index}>
            <div className="item">
              {v.config.name} &nbsp;
              {v.config.address} &nbsp;
              {additionConfigs.length > 0 &&
                additionConfigs
                  .filter((config) => config.id === v.id)
                  .map((config) => (
                    <div>
                      <label>name</label>
                      <input
                        value={config.config.name}
                        onChange={(e) => onChangeName(e, config.id)}
                      />
                      <label>address</label>
                      <input
                        value={config.config.address}
                        onChange={(e) => onChangeAddress(e, config.id)}
                      />
                    </div>
                  ))}
            </div>
            <button onClick={() => onAddBaseConfig(v)}>Add</button>
          </div>
        ))}
    </>
  );
}

目前,我使用config.id来更新额外的名称和地址,但有一个问题是,如果用户添加两个或更多额外的名称和地址输入,当更新第一个时,第二个也会更新。
如何分别更新?给每组输入一个标志?

dsekswqp

dsekswqp1#

假设组件不应修改由useEffect设置的基value,而是保留需要支持任意数量的配置输入的additionConfigs,也许一个解决方案可以是使additionConfigs状态成为对象。
additionConfigs对象可以将来自基本valueid作为键,将配置数组作为值,并且可能每个配置需要其自己的id,以便可以通过添加的input来控制它们,而无需对现有代码结构进行重大重构。
带修改的分叉:codesandbox
或许可以尝试以下示例:
additionConfigs状态定义为对象:

const [additionConfigs, setAdditionConfigs] = useState({});

添加配置input时更新additionConfigs的逻辑:
(* 这里的id逻辑只是添加了以前的id++,在实际项目中可能应该替换为唯一的id生成器 *)

const onAddBaseConfig = (item) => {
    setAdditionConfigs((preValue) => {
      const preConfigs = preValue?.[item.id];
      const newId = preConfigs
        ? preConfigs.reduce((acc, cur) => (cur.id > acc ? cur.id : acc), 0) + 1
        : 1;
      return {
        ...preValue,
        [item.id]: preConfigs
          ? [
              ...preConfigs,
              {
                id: newId,
                config: {
                  name: "",
                  address: ""
                }
              }
            ]
          : [
              {
                id: newId,
                config: {
                  name: "",
                  address: ""
                }
              }
            ]
      };
    });
  };

更新input的配置逻辑name,添加baseId作为参数,因为每个基本value可以有多个配置:

const onChangeName = (e, id, baseId) => {
    setAdditionConfigs((preValue) => {
      const newArr = preValue[baseId].map((v) => {
        if (v.id === id) {
          return {
            ...v,
            config: {
              ...v.config,
              name: e.target.value
            }
          };
        }
        return v;
      });
      return { ...preValue, [baseId]: newArr };
    });
  };

相同,但对于address

const onChangeAddress = (e, id, baseId) => {
    setAdditionConfigs((preValue) => {
      const newArr = preValue[baseId].map((v) => {
        if (v.id === id) {
          return {
            ...v,
            config: {
              ...v.config,
              address: e.target.value
            }
          };
        }
        return v;
      });
      return { ...preValue, [baseId]: newArr };
    });
  };

变更后的输出:

<>
  {value.length > 0 &&
    value.map((v, index) => (
      <div className="item" key={index}>
        <div className="item">
          {v.config.name} &nbsp;
          {v.config.address} &nbsp;
          {additionConfigs?.[v.id] &&
            additionConfigs?.[v.id].length > 0 &&
            additionConfigs?.[v.id].map((config, index) => (
              <div key={config.id}>
                <label>name</label>
                <input
                  value={config.config.name}
                  onChange={(e) => onChangeName(e, config.id, v.id)}
                />
                <label>address</label>
                <input
                  value={config.config.address}
                  onChange={(e) => onChangeAddress(e, config.id, v.id)}
                />
              </div>
            ))}
        </div>
        <button onClick={() => onAddBaseConfig(v)}>Add</button>
      </div>
    ))}
</>

相关问题