由Flux Store控制的React Form(最佳实践?)

Fer*_*gre 6 javascript forms reactjs reactjs-flux

所以我有一个很重要的组成部分:

<form>
 <FirstComponent value={this.state.firstValue}/>
 <SecondComponent value={this.state.secondValue}/>
 {more components here}
 <input type="submit" ... />
</form>
Run Code Online (Sandbox Code Playgroud)

这种形式的组件使用监听一个商店更新它的值firstAction,secondAction

注意:组件根据返回的store.getState()更新其状态 {firstValue: something, secondValue: something, etc}

所以让我们说我FirstComponent是一个输入:

<input type="text" value={this.props.value} 
   onChange={(e)=>this.props.firstAction(e.target.value)}
</input>
Run Code Online (Sandbox Code Playgroud)

好的,所以onChange触发了支柱firstAction,它实际上是Flux动作,它将更新我的商店并使表格重新渲染.我有两个好东西,当用户提交表单时,我可以检查我的商店中的FirstComponent的值,并且我还控制来自父组件的所有状态.

但是,onChange每次用户键入一个字符时,此回调将调用一个操作(因此它可以产生大量调用,因此重新渲染)< - 这会引发严重的性能问题吗?

相反,我可以使用refs,当用户按下提交按钮时,获取this.refs.myFirstComponent.state...我也将获得该值(这将是不受控制的组件?)但这听起来不像社区的推荐.

所以我的问题是,上面描述的第一种方法是一个很好的方法吗?我该如何优化它?那么只应该影响FirstComponent的重新渲染不会使SecondComponent等重新渲染?是shouldComponentUpdate唯一的出路吗?


编辑1:

第一种方法我面临一个问题......我使用WebdriverIO进行e2e测试,在文本字段中添加一个值:http://webdriver.io/api/action/setValue.html

我不知道为什么,但如果我试图在输入中添加"测试"这个词,webdriver只会添加最后一个字母.如果不使用状态/存储,这个问题就消失了.但是,如果我在内部拥有状态FirstComponent,例如:

<input type="text" value={this.state.value} 
   onChange={(e)=>this.setState({firstValue: e.target.value})}
   onBlur={()=>this.props.callback(this.state.firstValue)}
</input>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,组件在键入时似乎反应更快(仅渲染自身),然后,当用户移除焦点时,它会更新商店.我不得不说,我不喜欢这种方法,因为它不遵循你的状态(我觉得我复制状态)的模式但是它似乎工作得更快更重要:我的e2e测试工作.还有什么想法吗?

Bri*_*ark 3

您的第一种方法(即onChange触发 Flux 操作来更新商店并使您的表单重新渲染)似乎是一个不错的方法。我一直这样使用它,我也看到其他人也这样使用它。

关于您的以下评论:

但是,每次用户键入一个字符时,此 onChange 回调都会调用一个操作(因此它可能会产生大量调用,因此会重新渲染)<--这会引发严重的性能问题吗?

是的,我相信是这样。我曾经创建了一个包含许多其他组件以及一些输入字段的组件。每当我在输入字段中键入字符时,整个组件(及其包含的其他组件和输入字段)都会重新渲染,从而导致性能问题。如果我打字速度很快,这一点就会很明显。您实际上可以使用https://facebook.github.io/react/docs/perf.html来验证它。

无论如何,正如您提到的,我解决这个问题的方法是通过实施shouldComponentUpdate().

我想提一下的一个小技巧是创建一个自定义<Input />组件,它环绕<input />并实现shouldComponentUpdate() (即this.props.value !== nextProps.value || this.props.checked !== nextProps.checked)这样,如果您创建一个表单组件,例如,带有许多输入字段(使用自定义<Input />),则只有输入字段更改后会重新渲染。

不过,我也很想看看其他人如何解决这个问题。