简体   繁体   English

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

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

I have a nested object as state like below -我有一个嵌套的 object 作为 state 如下所示 -

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

I want to have 5 input fields - author, name, email, primary, and alternate and want to use only one handleChange() method to change the fields .我想要 5 个输入字段 - 作者、姓名、email、主要和备用字段,并且只想使用一个 handleChange() 方法来更改字段

You can find the code I wrote on the link - https://stackblitz.com/edit/react-ngpx7q您可以在链接上找到我写的代码 - https://stackblitz.com/edit/react-ngpx7q

Here, I am not able to figure out how to update the state correctly.在这里,我无法弄清楚如何正确更新 state。 Any help would be greatly appreciated.任何帮助将不胜感激。

Since this was an interview question then I'd avoid 3rd-party libraries.由于这是一个面试问题,所以我会避免使用 3rd-party 库。 You can use a switch statement to handle the differently nested state, namely the name and email in the second level and primary and alternate in the third level.您可以使用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
  }
};

Demo演示

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

you can use lodash set to assign the value for the deeply nested object.您可以使用 lodash set为深度嵌套的 object 分配值。 You need to pass the path to the name prop of your input.您需要将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>
  );
};

Now you can use a single handleChange method for updating all your keys in the state.现在您可以使用单个handleChange方法来更新 state 中的所有密钥。

Instead of treating phone as object of array, which i don't think is a good idea, treat it as single object with primary and alternate as key value pairs与其将电话视为数组的 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>
  );
}

This works based on your original data (where phone is an array of objects):这基于您的原始数据(其中 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}]
          }
        };
      });
    }
  };

I copy paste your code and only edit your handleChange我复制粘贴你的代码,只编辑你的 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