反应状态验证

时间:2016-03-02 17:32:38

标签: reactjs

我想在每个setState调用上对react组件执行状态验证,如果新状态无效,请使用另一个 - 有效状态。

例如,如果我有滑块,有4页,我想要

this.setState({
    page: 5
});

在我的验证功能中,我会检查新状态的值是否大于页数,如果是,我将设置4(总页数)而不是提供5。

这可能吗? 感谢

3 个答案:

答案 0 :(得分:1)

我不确定,但shouldComponentUpdate方法可能对您有帮助。

class Example extends React.Component {
  constructor(){
    super();
    this.state={
      count: 0
    }
    this.handleClick = this.handleClick.bind(this);
    this.reset = this.reset.bind(this);
  }
  shouldComponentUpdate(nextProps,nextState){
    return nextState.count <= 4
  }
  handleClick(){
    const newState = this.state.count + 1;
    this.setState({count: newState})  
  }
  reset(){
    this.setState({count: 0});
  }
  render(){
    return <div>
      <p>State: {this.state.count}</p>
      <button onClick={this.handleClick}>Click Me</button>
      <button onClick={this.reset}>Reset</button>
    </div>
  }
}
React.render(<Example />, document.getElementById('container'));

但是,它还取决于你的逻辑是否应该更新组件。 fiddle example

我希望它会对你有所帮助。

答案 1 :(得分:0)

是的,这当然是可能的。只需包裹setState,以便您可以在执行电话之前进行验证。类似的东西:

function checkThenSet(newState){
  // do validation here

  if (validation) {
    this.setState(newState);
  } else {
    // validation failed
    this.setState(otherState);
  }
}

如果您通过用户交互更新您的状态,那么您的渲染功能将如下所示

var MyComponent = React.createClass({

  checkThenSet: function(newState) {/* Same as above */},

  render: function() {
    return (<input
        type="text"
        value={this.state}
        onChange={this.checkThenSet}
      />);
  }
});

答案 2 :(得分:0)

尝试了很多事情之后,似乎没有一个很好的答案。 如果对这个问题有一个答案,那就可能是没有很好的办法。我认为查看潜在的解决方案以及每个解决方案的缺点并没有什么坏处。

解决方案1 ​​

使用 componentWillUpdate 已弃用

解决方案2

在渲染中验证状态-但在您和大多数情况下,验证可能会导致setState,setState会告诉您永远不要在render()中执行此操作,但不会涉及任何细节关于实际发生的事情。当然,您必须小心防止无限循环,但是如果您在某种情况下在render()中调用setState,而这些条件在逻辑上无法导致无限循环,那么会发生哪些意外的副作用?

解决方案3

如上所述,创建一个包装器功能,以同时验证和设置状态。但这在我看来是不好的,因为用设置状态直接完成的任何状态更改都无法得到验证。 setState不仅不会直接调用您的验证,而且您的验证也不会在初始状态的项目上运行。您可能会说,为什么要给组件一个无效的初始状态,但我不在乎,如果我想验证状态,我希望它在50000%的时间内都有效。

在一个复杂的表单示例中,还有其他问题。如果一个字段的有效性取决于另一个字段的状态怎么办?那么,仅在字段更改时重新验证字段的功能还不够。有人会说要测试传递的字段并调度多个事件以进行重新验证,但是同样,这对我来说是不可接受的。它不是完全可靠的,会导致错误,并使测试变得困难。

解决方案4

使用 componentWillReceiveProps 。不仅已弃用,还静态,这意味着您无权访问组件实例。对于某些组件,这很好,因为您仍然可以修改返回的状态,但是如果您的组件中的数据超出了状态和属性,则除了无法使用非静态方法外,您将无法访问它。意见使这种方法在许多情况下非常无用。

解决方案5

还没有测试过这个(对我来说,它相当疯狂),但是您可以在组件中覆盖setState 函数。在每个setState实例中插入一个回调。跟踪setState被调用的次数和setState回调被调用的次数。在回调内部,可以检查存储在对象中的两个计数器,以查看当前是否正在运行最后一个回调,然后运行一个验证所有状态的函数。在渲染时,将两个计数器都设置回零。我不建议这样做。它可能会起作用,但是它是一个非常强大的 hack

解决方案6

您可以使用 componentDidUpdate ,但这是低效的。您将使用未验证的值盲目设置状态,然后让组件渲染仅在之后进行验证,并可能再次调用render。同样,在componentDidUpdate中调用setState时,必须小心避免无限循环。我在其他地方读过,至少如果您在此处设置状态,则DOM将只重画一次。换句话说,它不会在render()之后立即绘制,而是要等到componentDidUpdate触发并在状态发生变化时重新调用render。这似乎是我所知道的唯一解决方案,它只会在不明确告诉您不要这样做的情况下发出警告。在您的情况下,效率并不重要,但是如果您要验证的状态是具有非常昂贵的渲染方法的100字段表单,该怎么办?现在,在每次按下键时,您实质上需要将渲染组件的工作量增加一倍,从而使组件先进行渲染而不进行验证,然后过滤和/或验证它们以进行第二次渲染。 / p>

其他问题

就我而言,我是在处理表单,而不是像上面所述的简单组件。我可能会混合使用解决方案3和5。它涉及使用一个函数来过滤,生成错误并为每个字段设置状态(即解决方案3)。然后,在componenetDidUpdate上,我可能会寻找状态键,其值与验证该字段的最后一个值不同。此处的第二步有很多方法,所有这些方法都是混乱且效率低下的。更糟糕的是,它们几乎永远不会在正常情况下运行,因为我总是使用第一个函数来更新和验证其状态,因此这使测试变得更加困难。这就像在我的应用中留下了一些似乎可以使用的后备,但是在整个开发过程中,除了我决定进行一次测试之外,它从未触发过。对我来说似乎是个坏主意。

我也不会涉及效率方面的其他问题,这涉及到如果字段的值与上次验证的值相同,则不要重新验证该字段。这是蠕虫的另一种形式,但基本上可以归结为,您不仅应该能够在渲染之前验证状态,而且还应该能够访问先前的状态,因此可以节省一些cpu时间并且仅验证已更改的字段。例如,如果您的文本区域很长,并且带有一些复杂的正则表达式,那么最好不要在每个组件渲染上都进行验证,即使它的单独字段正在更改。

事后

我非常失望,反应似乎没有为此提供任何合法的选择。看来您可以在一个操作中多次调用setState,并且每个操作都将排队,那么在解决所有状态更改后,他们又没有为我们提供 one 回调是怎么回事?渲染?好吧,如果您考虑一下,render函数本身就是这个回调函数,因为我认为它只有在setStates解决之后才被调用,但是同样,在render上调用setState是邪恶的,拥有render()会干净一百万倍。 )只是收到了正确的状态,所以我看不出这是多么有用。

有人知道为什么决定放弃componentWillUpdate吗?