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

时间:2018-05-25 23:34:04

标签: javascript forms reactjs state

我希望能够在React ES6中的表单组件状态中修改一些嵌套数据(对象内的对象)。我目前有一个可行的解决方案,但我觉得它可以更优雅地完成。

我想要修改的状态的形状是:

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

我希望能够在address: {}内添加/编辑数据。我目前的工作解决方案是:

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

如何让这个解决方案更优雅?有条件的必要吗?如果我想在同一个表单组件的状态中编辑其他嵌套对象,我该如何使它更具动态性呢?

如果我目前拥有的是正确的轨道,那么如何才能使this.setState()更加动态化address: {}?如何使它接受嵌套对象的任何名称,无论它是“地址”还是其他任何名称?

更新

从几分钟前开始,我想出了一个更精简,更有效的解决方案,我实际上比上面提到的更好。这是重构的解决方案:

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

所以使用这个新代码,我怎样才能让它更具动态性?更具体地说,如何根据正在更改的输入更加动态地更改const object = 'address';的值?

2 个答案:

答案 0 :(得分:0)

看看immutability-helper图书馆。它可以将您的代码转换为:

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

或者你甚至可以做到这样的事情:

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

答案 1 :(得分:0)

有两种方法可以实现“更优雅”,但不能实现相同的功能。首先是提取状态更新程序功能。在你的例子中,我会做这样的事情:

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

请注意,我使用的setState版本采用(prevState, props) => { partialState }形式的函数,并使用解构来从form传递prevState setState 1}}