繁体   English   中英

React - 使用嵌套对象作为 state 并带有钩子来填充表单数据

[英]React - using nested objects as state with hooks to fill form data

我有一个嵌套的 object 作为 state 如下所示 -

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

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

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

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

由于这是一个面试问题,所以我会避免使用 3rd-party 库。 您可以使用switch语句来处理不同嵌套的state,即第二层的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
  }
};

演示

编辑 react-handling-nested-objects-as-state-using-hooks

您可以使用 lodash set为深度嵌套的 object 分配值。 您需要将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方法来更新 state 中的所有密钥。

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

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>
  );
}

这基于您的原始数据(其中 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}]
          }
        };
      });
    }
  };

我复制粘贴你的代码,只编辑你的 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>
  );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM