【问题标题】:React - using nested objects as state with hooks to fill form dataReact - 使用嵌套对象作为带有钩子的状态来填充表单数据
【发布时间】:2021-08-13 22:04:57
【问题描述】:

我有一个嵌套对象,如下所示 -

const [userInfo, setUserInfo] = useState({
    author:"",
    user: {
      name: 'rahul',
      email: 'rahul@gmail.com',
      phone: [{ primary: '8888888810' }, { alternate: '7777777716' }]
    }
  });

我想要 5 个输入字段 - 作者、姓名、电子邮件、主要和备用字段,并且只想使用一个 handleChange() 方法来更改字段

你可以在链接上找到我写的代码-https://stackblitz.com/edit/react-ngpx7q

在这里,我无法弄清楚如何正确更新状态。任何帮助将不胜感激。

【问题讨论】:

  • 为什么要为手机使用对象数组?只需使用一个对象。
  • @YaakovAinspan 我在面试时遇到了这个问题。
  • @MattU 不完全是:(
  • 也许采访的一部分是为了识别次优的状态形状?平面对象在 UI 中使用起来很简单,您可以在提交到任何服务时嵌套属性或以其他方式创建新的对象形状。也许问题是通过点表示法识别嵌套属性,即id="user.phone.primary",他们希望您编写逻辑来拆分它并递归访问正确的属性。希望你问清楚他们想要什么的问题,有时面试问题是故意模棱两可的。

标签: javascript reactjs react-hooks state javascript-objects


【解决方案1】:

因为这是一个面试问题,所以我会避免使用第 3 方库。您可以使用switch 语句来处理不同的嵌套状态,即第二级的nameemail,以及第三级的primaryalternate

const handleChange = (e) => {
  const { name, value } = e.target;

  switch (name) {
    case "name":
    case "email":
      setUserInfo((userInfo) => ({
        user: {
          ...userInfo.user,
          [name]: value
        }
      }));
      break;

    case "primary":
    case "alternate":
      setUserInfo((userInfo) => ({
        user: {
          ...userInfo.user,
          phone: userInfo.user.phone.map((el) =>
            el.hasOwnProperty(name)
              ? {
                  [name]: value
                }
              : el
          )
        }
      }));
      break;

    default:
    // ignore
  }
};

演示

【讨论】:

  • 感谢您的代码。但我无法更改代码中备用输入的值。我尝试调试代码,但也找不到任何错误。
  • @MohitChauhan 哦,非常抱歉,我使用secondary 而不是alternate 作为处理程序中的第二个电话字段名称切换案例。我更新了我的答案并链接了代码框。请再次检查。
【解决方案2】:

您可以使用 lodash set 为深度嵌套的对象分配值。您需要将path 传递给您输入的name 属性。

import set from 'lodash/set'

const App = () => {
  const [userInfo, setUserInfo] = useState({
    author:"",
    user: {
      name: 'rahul',
      email: 'rahul@gmail.com',
      phone: [{ primary: '8888888810' }, { alternate: '7777777716' }]
    }
  });

  const handleChange = (e) => {
    // clone the state
    const userInfoCopy = JSON.parse(JSON.stringify(userInfo));
    set(userInfoCopy, e.target.name, e.target.value)
    setUserInfo(userInfoCopy)
  }

  console.log(userInfo)

  return (
    <div>
      <input
        name="user.name"
        onChange={handleChange}
      />
       <input
        name="user.phone.[0].primary"
        onChange={handleChange}
      />     
    </div>
  );
};

现在您可以使用单个 handleChange 方法来更新状态中的所有密钥。

【讨论】:

    【解决方案3】:

    与其将 phone 视为数组的对象(我认为这不是一个好主意),不如将其视为单个对象,将主要和备用作为键值对

    import React, { useState } from 'react';
    import './style.css';
    
    export default function App() {
      const [userInfo, setUserInfo] = useState({
        user: {
          name: 'ravi',
          email: 'ravi@gmail.com',
          phone: {
            primary: 345345345345,
            alternate: 234234234234
          }
        }
      });
    
      const handleChange = e => {
        console.log(e.target.name);
        setUserInfo(prevState => {
          return {
            user: {
              ...prevState.user,
              [e.target.name]: e.target.value,
              phone: {
                ...prevState.user.phone,
                ...{ [e.target.name]: e.target.value }
              }
            }
          };
        });
      };
    
      const {
        name,
        email,
        phone: { primary, alternate }
      } = userInfo.user;
    
      console.log(userInfo);
    
      return (
        <div className="App">
          Name: <input name="name" value={name} onChange={e => handleChange(e)} />
          <br />
          Email:{' '}
          <input name="email" value={email} onChange={e => handleChange(e)} />
          <br />
          Primary:{' '}
          <input name="primary" value={primary} onChange={e => handleChange(e)} />
          <br />
          Alternate:{' '}
          <input
            name="alternate"
            value={alternate}
            onChange={e => handleChange(e)}
          />
          <br />
        </div>
      );
    }
    

    【讨论】:

    • 给出错误。电话不是对象而是数组
    【解决方案4】:

    这基于您的原始数据(其中 phone 是一个对象数组):

    const handleChange = e => {
        let name = e.target.name;
        if (['name', 'email'].includes(name)) {
          setUserInfo(prevState => {
            return {
              user: {
                ...prevState.user,
                [name]: e.target.value,
              }
            };
          });
        } else {
          setUserInfo(prevState => {
            return {
              user: {
                ...prevState.user,
                phone: name === 'primary' ?
                 [prevState.user.phone.find(e => Object.keys(e).includes('alternate')), {[name]: e.target.value}] :
                 [prevState.user.phone.find(e => Object.keys(e).includes('primary')), {[name]: e.target.value}]
              }
            };
          });
        }
      };
    

    【讨论】:

      【解决方案5】:

      我复制粘贴你的代码,只编辑你的 handleChange

      import React, { useState } from 'react';
      import './style.css';
      
      export default function App() {
        const [userInfo, setUserInfo] = useState({
          user: {
            name: 'ravi',
            email: 'ravi@gmail.com',
            phone: [{ primary: '9999999990' }, { alternate: '9999998880' }]
          }
        });
      
      
      
        const handleChange = e => {
          console.log(e.target.name);
          let arrPhone = userInfo.user.phone;
          (e.target.name == 'primary' || e.target.name == 'alternate' ) 
          && arrPhone.map(x => (x.hasOwnProperty(e.target.name)) && (x[e.target.name] = e.target.value))
      
          console.log(arrPhone)
          setUserInfo(prevState => {
            return {
              user: {
                ...prevState.user,
                [e.target.name]: e.target.value,
                phone: arrPhone
              }
            };
          });
        };
      
        const {
          name,
          email,
          phone: [{ primary }, { alternate }]
        } = userInfo.user;
      
        console.log(userInfo);
      
        return (
          <div className="App">
            Name: <input name="name" value={name} onChange={handleChange} />
            <br />
            Email: <input name="email" value={email} onChange={handleChange} />
            <br />
            Primary: <input name="primary" value={primary} onChange={handleChange} />
            <br />
            Alternate:{' '}
            <input name="alternate" value={alternate} onChange={handleChange} />
            <br />
          </div>
        );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-29
        • 1970-01-01
        • 2017-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-16
        • 2021-12-10
        相关资源
        最近更新 更多