【问题标题】:How to elegantly modify nested data within a form component's state in React ES6?如何在 React ES6 中优雅地修改表单组件状态中的嵌套数据?
【发布时间】:2018-05-25 23:34:04
【问题描述】:

我希望能够在 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,
                  },
              });
    }

我怎样才能使这个解决方案更优雅?条件是必要的吗?如果我想在同一个表单组件的状态下编辑其他嵌套对象,如何使这更加动态?

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


更新

几分钟前,我想出了一个更精简、更有效的解决方案,我实际上比上面的那个更喜欢这个解决方案。这是重构的解决方案:

    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'; 的值?

【问题讨论】:

  • 三重表达和优雅永远不会混在同一个句子里。我们在工作中这样做的方式是尝试在一个方法中只调用 1 个 setState 函数。构建您想要分配的对象(有条件地)然后setState({ form : newState });
  • 有趣的是,您在几分钟前提到了这一点React 文档更准确。我将编辑我的原始问题以包括我想出的内容。希望您能提供进一步的意见。谢谢!

标签: javascript forms reactjs state


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    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 } 形式的函数,并使用解构从prevState 中获取form,从setState 传递过来

    【讨论】:

      猜你喜欢
      • 2017-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 2021-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多