javascript 在React中动态添加处理程序和状态

kokeuurv  于 2022-12-21  发布在  Java
关注(0)|答案(4)|浏览(140)

我需要为数组的每个名称呈现大量的输入,但问题是为每个呈现的输入动态创建useState常量和onChange处理程序。我尝试为数组中的每个项创建handleChange键,并将其传递给input onChange,但得到了“String而不是Function”错误。如何用另一种方法解决这个问题,同时避免代码重复?

export const myArr = [
  { name: "Crist", data: "crist", color: "lightblue", handleChange: "cristHandleChange"},
  { name: "Ruby", data: "ruby", color: "lightpink", handleChange: "rubyHandleChange"},
  { name: "Diamond", data: "diamond", color: "white", handleChange: "diamondHandleChange"},
];

export const myComponent = () => {
  const [cristQuantity, setCristQuantity] = useState(0);
  const [rubyQuantity, setRubyQuantity] = useState(0);
  const [diamondQuantity, setDiamondQuantity] = useState(0);

  function cristHandleChange(event) {
    setCristQuantity(event.target.value);
  }

  function rubyHandleChange(event) {
    setRubyQuantity(event.target.value);
  }

  function diamondHandleChange(event) {
    setDiamondQuantity(event.target.value);
  }

  return (
    <>
      {myArr
        ? myArr.map((item, index) => (
            <div className="main-inputs__wrapper" key={`item${index}`}>
              <label htmlFor={item.data}>{item.name}</label>
              <input
                type="number"
                name={item.data}
                style={{ background: item.color }}
                onChange={item.handleChange} //???
              />
            </div>
          ))
        : null}
    </>
  );
};
6uxekuva

6uxekuva1#

我还没有真正测试过这个,但这是我会做的事情,这将让你的方式。

export const myArr = [
    {
        name: `Crist`,
        data: `crist`,
        color: `lightblue`,
        handleChange: `cristHandleChange`,
    },
    {
        name: `Ruby`,
        data: `ruby`,
        color: `lightpink`,
        handleChange: `rubyHandleChange`,
    },
    {
        name: `Diamond`,
        data: `diamond`,
        color: `white`,
        handleChange: `diamondHandleChange`,
    },
]

export const myComponent = () => {
    const [quantities, setQuantities] = useState({
        crist: 0,
        ruby: 0,
        diamond: 0,
    })

    const onChangeHandler = ({ name, value }) => {
        setQuantities((prevState) => ({ ...prevState, [name]: value }))
    }

    return (
        <>
            {myArr.length > 0
                ? myArr.map(({ data, name, color }, index) => {
                    // if you need to do an update to push more items to the object for any dynamic reason
                        if (!quantities.name)
                            setQuantities((prevState) => ({ ...prevState, [name]: 0 }))
                        return (
                            <div className="main-inputs__wrapper" key={`item${index}`}>
                                <label htmlFor={data}>{name}</label>
                                <input
                                    type="number"
                                    name={name}
                                    value={quantities.name}
                                    style={{ background: color }}
                                    onChange={(e) =>
                                        onChangeHandler({ name, value: e.currentTarget.value })
                                    }
                                />
                            </div>
                        )
                  })
                : null}
        </>
    )
}
juud5qan

juud5qan2#

您正在向onChange传递字符串(而不是函数),这导致了该问题。
要修复此问题,可以将所有函数 Package 到另一个对象中

const onChangeFunctions = {
    cristHandleChange: (event) => {
      setCristQuantity(event.target.value);
    },
    rubyHandleChange: (event) => {
      setRubyQuantity(event.target.value);
    },
    diamondHandleChange: (event) => {
      setDiamondQuantity(event.target.value);
    },
  };

并调用onChangeFunctions[item.handleChange],如下所示

export const myArr = [
  {
    name: "Crist",
    data: "crist",
    color: "lightblue",
    handleChange: "cristHandleChange",
  },
  {
    name: "Ruby",
    data: "ruby",
    color: "lightpink",
    handleChange: "rubyHandleChange",
  },
  {
    name: "Diamond",
    data: "diamond",
    color: "white",
    handleChange: "diamondHandleChange",
  },
];

export const myComponent = () => {
  const [cristQuantity, setCristQuantity] = useState(0);
  const [rubyQuantity, setRubyQuantity] = useState(0);
  const [diamondQuantity, setDiamondQuantity] = useState(0);

  const onChangeFunctions = {
    cristHandleChange: (event) => {
      setCristQuantity(event.target.value);
    },
    rubyHandleChange: (event) => {
      setRubyQuantity(event.target.value);
    },
    diamondHandleChange: (event) => {
      setDiamondQuantity(event.target.value);
    },
  };

  return (
    <>
      {myArr
        ? myArr.map((item, index) => (
            <div className="main-inputs__wrapper" key={`item${index}`}>
              <label htmlFor={item.data}>{item.name}</label>
              <input
                type="number"
                name={item.data}
                style={{ background: item.color }}
                onChange={onChangeFunctions[item.handleChange]}
              />
            </div>
          ))
        : null}
    </>
  );
};
gdrx4gfi

gdrx4gfi3#

首先,您可能希望使用React Hook Form这样的库来实现这一点,不过,如果这是唯一的表单,并且您不需要所有的花哨特性(或额外的bundle大小),您也可以这样做。
第一步是将表单数据存储在Object中,在此更改之后,您可以使用单个useState({})来存储和读取表单数据,从而大大简化了处理程序。
例如:

export const myArr = [
  { name: "Crist", data: "crist", color: "lightblue"},
  { name: "Ruby", data: "ruby", color: "lightpink"},
  { name: "Diamond", data: "diamond", color: "white"},
];

// generate Object with data and initialValue or empty string
// e.g. `{ 'crist': '', 'ruby': '', 'diamond': '' }`
const getInitialFormValues = (arr) => Object.fromEntries(
  arr.map(({ data, initialValue }) => [data, initialValue || ''])
);

export const MyComponent = () => {
  const [formValues, setFormValues] = useState(getInitialFormValues(myArr));

  function handleChange(event) {
    // update the changed form value
    setFormValues(current => ({ 
      ...current, // other form values
      [event.target.name]: event.target.value // updated value
    }));
  }

  return (
    <>
      {myArr
        ? myArr.map((item, index) => (
            <div className="main-inputs__wrapper" key={`item${index}`}>
              <label htmlFor={item.data}>{item.name}</label>
              <input
                type="number"
                name={item.data}
                style={{ background: item.color }}
                onChange={handleChange}
                value={formValues[item.data]}
              />
            </div>
          ))
        : null}
    </>
  );
};
n3h0vuf2

n3h0vuf24#

您应该为所有输入创建一个处理程序,并将值保存在一个带有键的对象中,如item.data。第一个月

export const myArr = [
  {
    name: "Crist",
    data: "crist",
    color: "lightblue"
  },
  {
    name: "Ruby",
    data: "ruby",
    color: "lightpink"
  },
  {
    name: "Diamond",
    data: "diamond",
    color: "white"
  }
];

export function MyComponent() {
  // Lazy initial state 
  // https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
  const [quantities, setQuantities] = useState(() =>
    myArr.reduce((initialQuantities, item) => {
      initialQuantities[item.data] = 0;
      return initialQuantities;
    }, {})
  );

  // common handler for every onChange with computed property name
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names
  const handleChange = (event) => {
    setQuantities((prevQuantities) => ({
      ...prevQuantities,
      [event.target.name]: event.target.value
    }));
  };

  return (
    <>
      {Array.isArray(myArr)
        ? myArr.map((item, index) => (
            <div className="main-inputs__wrapper" key={`item${index}`}>
              <label htmlFor={item.data}>{item.name}</label>
              <input
                type="number"
                name={item.data}
                style={{ background: item.color }}
                onChange={handleChange}
                value={quantities[item.data] || ""}
              />
            </div>
          ))
        : null}
    </>
  );
}

相关问题