反应 - 有一个主要的setState函数还是多个?

时间:2018-02-02 01:13:31

标签: reactjs

我一直在React开发一段时间。当我刚开始时,我的代码看起来像这样:

this.state = {
  foo: 1,
  bar: 2,
  baz: 3
};

updateFoo(num) {
  this.setState({ foo: num )};
}

updateBar(num) {
  this.setState({ bar: num )};
}

updateBaz(num) {
  this.setState({ baz: num )};
}

用于更新状态的单独部分的单独函数。

后来我意识到,嗯这是一个很好的推导者,让我们改变一切。因此,对于每个状态更新而不是单独的函数,我去了类似的东西:

updateState(key, val) {
  this.setState([key]: val);
}

我一直在使用 updateState 进行非常简单的状态更新。我喜欢它,但我意识到我可以更进一步,传递一个完整的更新对象来更新多个状态:

updateManyStates(state) {
  this.setState(state);
}

updateManyStates({ foo: 5, bar: 6, baz: 7 });

在编写 updateManyStates 函数后,我觉得我的代码变得不那么清晰了。虽然多余,但 updateFoo updateBar updateBaz 等功能清楚地显示了我的代码中发生了什么。 updateManyStates 非常干,但有时我觉得它比其他开发人员更容易消化。想法?

2 个答案:

答案 0 :(得分:1)

我想说的是要记住的是尽量使用你选择的任何模式和命名标准保持一致。如果您认为有多个更新方法可以创建清晰易读的代码,那么请坚持使用它。

就个人而言,我认为不仅功能模式,而且命名标准对于创建可读代码也很重要。例如,我很少在Component中创建名称为update...的函数。该命名标准作为我的Action处理程序更常见。我在组件内部尝试的方法是使用名为handle...的方法,即handleChangehandleClick等。因此,对setState的调用主要是从这些句柄中调用的功能。如果这些方法传递给子组件,它们将被分配到on...属性,即onChangeonClick

但是为了与原始问题相关,因为我有多个函数作为处理程序,所以在多个函数和上下文中重复调用setState。

作为旁注,我确实在您的示例中看到了一个问题,即每次调用setState都将替换所有现有属性。例如,如果您从初始状态开始

this.state = {
  foo: 1,
  bar: 2,
  baz: 3
};

然后您致电this.setState({ foo: num )};,然后this.state不再拥有任何barbaz个键/值,因为整个对象已被替换。 ReactJS文档建议用于处理此问题的方法是使用其不可变辅助函数update(请参阅Immutability Helpers - React)。根据您使用的React版本,您可以在不同的包中找到它。

要仅更新一个键/值并保留其余值,请执行以下操作:

this.setState(update(this.state, {
  foo: { $set: "new value" }
}));

<击>

以下是我的项目中可能是基本组件的示例。

import { updateUser } from '../actions/UserActions';

class MyComponent extends Component {

  constructor(props) {
    super();

    this.state = {
      first: "",
      last: "",
      hasChanges: false
    };

    this.handleChangeFirst = this.handleChangeFirst.bind(this);
    this.handleChangeLast = this.handleChangeLast.bind(this);
    this.handleClickSave = this.handleClickSave.bind(this);
  }

  handleChangeFirst(event) {
    this.setState({
      first:      event.target.value,
      hasChanges: true
    });
  }

  handleChangeLast(event) {
    this.setState({
      last:       event.target.value,
      hasChanges: true
    });
  }

  handleClickSave() {
    const { first, last } = this.state;

    updateUser({ first, last });

    this.setState({
      hasChanges: false
    });
  }

  render() {
    const { first, last, hasChanges } = this.state;

    return (
      <div>
        <input
          type="text"
          value={first}
          onChange={this.handleChangeFirst}
        />
        <input
          type="text"
          value={last}
          onChange={this.handleChangeLast}
        />
        <input
          type="button"
          value="Save"
          onClick={this.handleClickSave}
          disabled={!hasChanges}
      </div>
    );
  }
}

作为最后一个提示,如果您担心干扰代码,我可以通过将handle函数多次绑定到不同的属性来实现与上面示例相同的结果,如下所示:

constructor(props) {
  super();

  this.state = {
    first: "",
    last: ""
  };

  this.handleChangeFirst = this.handleChange.bind(this, "first");
  this.handleChangeLast = this.handleChange.bind(this, "last");
}

handleChange(attr, event) {
  this.setState(update(this.state, {
    [attr]:     event.target.value,
    hasChanges: true
  });
}

也许我过于复杂化,但我希望这可以提供一些关于如何构建事物的想法,继续前进。

编辑:提供有关setState的错误信息。

答案 1 :(得分:0)

使用命名良好的方法执行对本地组件状态的特定更新没有任何问题。实际上,我更喜欢它,因为这些方法经常被传递到下游的其他组件,并使跟踪逻辑变得更容易。

在每种方法中调用this.setState几乎与DRY的概念不一致。