Json 反应:在设置状态的事件中传递一个道具

Json 反应:在设置状态的事件中传递一个道具,json,reactjs,events,nested,state,Json,Reactjs,Events,Nested,State,我正在使用一个嵌套状态对象,我一直在使用onChange函数更新它,如下所示: const [someState, setSomeState] = useState({ customer: [ { name: "Bob", address: "1234 Main Street", email: "bob@mail.com", phone: [ { mobile: "

我正在使用一个嵌套状态对象,我一直在使用onChange函数更新它,如下所示:

  const [someState, setSomeState] = useState({
    customer: [
      {
        name: "Bob",
        address: "1234 Main Street",
        email: "bob@mail.com",
        phone: [
          {
            mobile: "555-5555",
            home: "555-5555"
          }
        ]
      }
    ]
  });

  const updateSomeStatePhone = e => {
    e.persist();
    setSomeState(prevState => {
      prevState.customer[0].phone[0].mobile = e.target.value;
      return {
        ...prevState
      };
    });
  };

 <p>Update Mobile Number<p>
  <select
   value={someState.customer[0].phone[0].mobile}
   onChange={updateSomeStatePhone}
  >
   <option value="123-4567">"123-4567"</option>
  </select>

但是函数从不识别我从函数传入的“道具”。我相信一定有一个简单的方法可以做到这一点。任何帮助都将不胜感激。

请使用lodash的助手


顺便说一句,在您现有的
updateStatePhone
中,您正在修改
prevState
对象,该对象应该是不可变的。

它必须是单个
useState
钩子吗?我建议使用
useReducer
或使用多个
useState
挂钩将其简化一点

多个
useState
hook

useReducer
是一个更好的选择。互联网上到处都是例子

为什么不应该使用
useState
传递对象,是因为它的行为不像
setState
。基础对象引用是相同的。因此,react永远不会触发状态更改。如果要对对象使用相同的
useState
。您可能需要实现自己的版本来扩展它(下面的例子),或者您可以直接使用hook来实现相同的功能

下面是一个使用
useState
的示例,让您注意到每次更改时的状态更新

const [form, setValues] = useState({
    username: "",
    password: ""
});

const updateField = e => {
    setValues({
      ...form,
      [e.target.name]: e.target.value
    });
};
注意那里的
…表单
。您可以在每次更新中这样做,也可以使用自己的实用程序或我提到的
useReducer

现在谈到您的代码,还有其他问题

  • 您正在使用
    手机
    作为一个数组,可以是一个对象。或者更好的是,单独的属性也可以。没有害处

  • 如果将
    客户
    作为一个数组,则必须循环浏览记录。不仅仅是通过硬编码来更新索引。如果只有一个客户,最好不要保留阵列,而只保留一个对象。假设它是一个客户阵列,并且您在其中循环,下面介绍如何更新
    mobile

  • 相反,我更希望只有一个onChange处理程序,并传入 我所在的状态属性的表单字段中的状态 正在更改,但我无法理解语法

    如果您还没有从第一个示例中了解到这一点。以下是如何在短短的步骤

  • 给HTML元素一个name属性
  • 然后改用
    [e.target.name]

  • 非常感谢您的回复。我将调查用户教育者。不幸的是,我无法更改正在使用的状态对象的结构。否则,我肯定看到了重组状态和使用你建议的方法的价值。我没有说你是强制使用它的。我从useState和use Reducer的角度解释了使用what和what NOT的原因。另外,我指出了不使用循环来更新应该更新的位置的方法。如果是一次性更新,则为另一种情况。感谢您至少对我的回答表示感谢。非常感谢您的回复。问题是。与@ckedar推荐的lodash相比,使用还原剂是否有任何优势?这似乎是访问嵌套项的最干净的方式。嗯,他似乎删除了他的评论。无所谓。我还注意到reducer函数是在组件外部声明的。如果我将此组件与许多其他具有减速器的类似组件一起导入,这会导致问题吗?一个优点是,使用减速器,您可以更灵活地精确控制状态。您还可以为每个操作/字段执行独特的操作,并添加新操作(例如:清除或重置)。而且它不需要添加另一个依赖项(因为它是香草反应)。如果我需要以上面列出的原始状态访问第二个“customer”数组对象来设置名称(state.customer[1].name),该怎么办?我似乎找不到正确的语法。我得到了以下内容:``case“SET_CUST1_NAME”:返回{…state,customer:[{…state.customer[1],NAME:value}]```使用它比使用减速机有什么好处吗?@yummylumpkins-Less样板代码。如果向客户添加新属性,则不需要更改更新代码。我们可以使用u.set编写reducer来消除样板代码,但一般来说,在处理更复杂的状态时,我将使用reducer,该状态的组件之间存在交互/相互依赖关系。
    prevState.prop = e.target.value;
    
    prevState.(prop) = e.target.value;
    
    ${prevState} + '.' + ${prop} = e.target.value; // Dumb, I know
    
    const updateSomeState = (e, prop) => {
        e.persist();
        setSomeState(prevState => {
          let customers = [...prevState.customers] // make a copy of array
          let customer = {...customers[0]} // make a copy of customer object
          _.set(customer, prop, e.target.value)
          customers[0] = customer;
          return {
            ...prevState, customers 
          };
        });
      };
    
    import React from "react";
    import ReactDOM from "react-dom";
    
    import "./styles.css";
    
    function App() {
      const [name, setName] = React.useState("");
      const [address, setAddress] = React.useState("");
      const [email, setEmail] = React.useState("");
      const [mobile, setMobile] = React.useState("");
      const [home, setHome] = React.useState("");
    
      const getResult = () => ({
        customer: [
          {
            name,
            address,
            email,
            phone: [
              {
                mobile,
                home
              }
            ]
          }
        ]
      });
    
      // Do whatever you need to do with this
      console.log(getResult());
    
      return (
        <>
          <input
            value={name}
            placeholder="name"
            onChange={e => setName(e.target.value)}
          />
          <br />
          <input
            value={address}
            placeholder="address"
            onChange={e => setAddress(e.target.value)}
          />
          <br />
          <input
            value={email}
            placeholder="email"
            onChange={e => setEmail(e.target.value)}
          />
          <br />
          <input
            value={mobile}
            placeholder="mobile"
            onChange={e => setMobile(e.target.value)}
          />
          <br />
          <input
            value={home}
            placeholder="home"
            onChange={e => setHome(e.target.value)}
          />
        </>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    
    const [form, setValues] = useState({
        username: "",
        password: ""
    });
    
    const updateField = e => {
        setValues({
          ...form,
          [e.target.name]: e.target.value
        });
    };
    
    const updatedCustomers =  state.customers.map(item => {
    
       const { phone } = item;
       return { ...item, phone: { mobile: e.target.value }}; 
       // returns newCustomer object with updated mobile property
    });
    
    // Then go ahead and call `setSomeState ` from `useState`
    setSomeState(...someState, { customer: updatedCustomers });// newState in your case is 
    
       return { ...item, phone: { [e.target.name]: e.target.value }};