简体   繁体   English

如何在React ES6中优雅地修改表单组件状态内的嵌套数据?

[英]How to elegantly modify nested data within a form component's state in React ES6?

I want to be able to modify some nested data (an object within an object) within my form component's state in React ES6. 我希望能够在React ES6的表单组件状态下修改一些嵌套数据(对象内的对象)。 I currently have a working solution but I feel like it could be accomplished more elegantly. 我目前有一个可行的解决方案,但我觉得可以更优雅地完成。

The shape of the state that I want to modify is: 我要修改的状态的形状是:

    this.state = {
        form: {
            address: {},
        },
    };

I want to be able to add/edit data within address: {} . 我希望能够在address: {}添加/编辑数据。 The current working solution I have is: 我目前的工作解决方案是:

    onChange(event) {
        const { form } = this.state;
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;

        name === 'street' || name === 'city'
            ? this.setState({
                  form: {
                      ...form,
                      address: {
                          ...form.address,
                          [name]: value,
                      },
                  },
              })
            : this.setState({
                  form: {
                      ...form,
                      [name]: value,
                  },
              });
    }

How can I make this solution more elegant? 如何使该解决方案更优雅? Is the conditional necessary? 有条件必要吗? How can I make this more dynamic if I were to want to edit other nested objects within this same form component's state? 如果要在同一表单组件状态下编辑其他嵌套对象,如何使它更具动态性?

If what I currently have is on the right track, how can I make the this.setState() that modifies address: {} more dynamic? 如果我目前所处的位置正确,如何使this.setState()修改address: {}更动态? How can I make this accept any name for the nested object whether it is "address" or anything else? 如何使它接受嵌套对象的任何名称,无论是“地址”还是其他名称?


UPDATE 更新

As of a few minutes ago I came up with a leaner, working solution that I am actually liking better than the one I have above. 几分钟前,我想出了一个更精简,有效的解决方案,实际上我比上面的解决方案更喜欢。 Here is the refactored solution: 这是重构的解决方案:

    onChange(event) {
        const { form } = this.state;
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;
        const object = 'address';

        name === 'street' || name === 'city'
            ? (form[object][name] = value)
            : (form[name] = value);
        this.setState({
            form,
        });
    }

So with this new code, how can I make this more dynamic? 因此,使用此新代码,如何使它更具动态性? More specifically, how can I change the value of const object = 'address'; 更具体地说,如何更改const object = 'address'; more dynamically depending on the input that is being changed? 更动态地取决于正在更改的输入?

Take a look at immutability-helper library. 看一看不变性帮助程序库。 It can turn your code into: 它可以将您的代码变成:

  onChange(event) {
    const { type, checked, value, name } = event.target;

    const updatedValue = type === 'checkbox' ? checked : value;

    this.setState(state => {
      if (name === 'street' || name === 'city') {
        return {
          form: update(state.form, {
            address: {
              [name]: { $set: updatedValue },
            },
          })
        };
      }

      return {
        form: update(state.form, {
          [name]: { $set: updatedValue },
        }),
      }
    });
  }

Or you could do even something like this: 或者,您甚至可以执行以下操作:

onChange(event) {
    const { type, checked, value, name } = event.target;

    const updatedValue = type === 'checkbox' ? checked : value;
    const updatedObject = { [name]: { $set: updatedValue } };

    this.setState(state => ({
      form: update(state.form, (name === 'street' || name === 'city') ? { address: updatedObject } : updatedObject)
    }));
  }

There are a couple of ways that you can achieve something "more elegant", but not on the same function. 有两种方法可以实现“更优雅”的功能,但不能实现同一功能。 The first thing would be to extract state updater functions. 第一件事是提取状态更新程序功能。 On your example I would do something like this: 在您的示例中,我将执行以下操作:

const updateForm = (key, value) => ({form}) => ({ ...form, [key]: value });

const updateAddress = (key, value) => updateForm("address", {...form.address, [key]: value});

onChange(event) {
   const { form } = this.state;
   const target = event.target;
   const value = target.type === 'checkbox' ? target.checked : target.value;
   const name = target.name;

   if (name === 'street' || name === 'city') {
     this.setState(updateAddress(name, value));
   } else {
     this.setState(updateForm(name, value));
   }
}

Note that I'm using the version of setState that takes a function of the form (prevState, props) => { partialState } and using destructuring to take form from the prevState passed from setState 请注意,我正在使用setState的版本,该版本采用形式(prevState, props) => { partialState }函数,并使用解构从setState传递的prevState form

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

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