在React表单中道具更新状态更新

我在使用React表单和正确管理状态时遇到麻烦。我有一个形式为模式的时间输入字段。初始值在中设置为状态变量getInitialState,并从父组件传入。这本身工作正常。

当我想通过父组件更新默认的start_time值时,就会出现问题。更新本身通过发生在父组件中setState start_time: new_time但是在我的表单中,默认的start_time值从不更改,因为它仅在中定义一次getInitialState

我曾尝试通过componentWillUpdate强制进行状态更改setState start_time: next_props.start_time,该更改确实有效,但给了我Uncaught RangeError: Maximum call stack size exceeded错误。

所以我的问题是,在这种情况下更新状态的正确方法是什么?我是否以某种方式在考虑这个错误?

当前代码:

@ModalBody = React.createClass
  getInitialState: ->
    start_time: @props.start_time.format("HH:mm")

  #works but takes long and causes:
  #"Uncaught RangeError: Maximum call stack size exceeded"
  componentWillUpdate: (next_props, next_state) ->
    @setState(start_time: next_props.start_time.format("HH:mm"))

  fieldChanged: (fieldName, event) ->
    stateUpdate = {}
    stateUpdate[fieldName] = event.target.value
    @setState(stateUpdate)

  render: ->
    React.DOM.div
      className: "modal-body"
      React.DOM.form null,
        React.createElement FormLabelInputField,
          type: "time"
          id: "start_time"
          label_name: "Start Time"
          value: @state.start_time
          onChange: @fieldChanged.bind(null, "start_time”)

@FormLabelInputField = React.createClass
  render: ->
    React.DOM.div
      className: "form-group"
      React.DOM.label
        htmlFor: @props.id
        @props.label_name + ": "
      React.DOM.input
        className: "form-control"
        type: @props.type
        id: @props.id
        value: @props.value
        onChange: @props.onChange
飞云小胖2020/03/11 11:47:36

从他们的文档中可以很明显地看出来:

If you used componentWillReceiveProps for re-computing some data only when a prop changes, use a memoization helper instead.

使用:https : //reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#what-about-memoization

A逆天猿2020/03/11 11:47:36

也有componentDidUpdate可用。

功能签名:

componentDidUpdate(prevProps, prevState, snapshot)

组件更新后,可以以此为契机在DOM上进行操作。不会在initial上被调用render

看到您可能不需要派生状态文章,该文章描述了componentDidUpdate和的反模式getDerivedStateFromProps我发现它非常有用。

小哥Eva2020/03/11 11:47:36

来自react文档:https : //reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

道具更改时的擦除状态是反模式

从React 16开始,componentWillReceiveProps被弃用。从反应文档中,在这种情况下,推荐的方法是使用

  1. 完全控制组件:在ParentComponentModalBody将自己的start_time状态。在这种情况下,这不是我的首选方法,因为我认为模态应该拥有该状态。
  2. 完全不受控制的组件,带有一个键:这是我的首选方法。react文档中的一个示例:https : //codesandbox.io/s/6v1znlxyxn您将完全拥有自己的start_time状态ModalBody并使用getInitialState它,就像您已经做过的那样。要重置start_time状态,您只需从ParentComponent
NearItachi2020/03/11 11:47:36

您可能不需要派生状态

1.设置父项的密钥

当一个键改变时,React将创建一个新的组件实例,而不是更新当前实例。键通常用于动态列表,但在这里也很有用。

2.使用getDerivedStateFromProps/componentWillReceiveProps

如果密钥由于某种原因而无法使用(也许该组件初始化非常昂贵)

通过使用,getDerivedStateFromProps您可以重置状态的任何部分,但此时似乎有点问题(v16.7)!,有关用法,请参见上面的链接

Pro逆天猿2020/03/11 11:47:36

componentWillReceiveProps 已被弃用,因为使用它“通常会导致错误和不一致”。

如果外面有什么变化,请考虑使用完全重置子组件key

key子组件提供支持可确保无论何时key外部更改的值都会重新渲染该组件。例如,

<EmailInput
  defaultEmail={this.props.user.email}
  key={this.props.user.id}
/>

关于其性能:

尽管这听起来可能很慢,但性能差异通常并不明显。如果组件具有繁琐的逻辑以在更新上运行,则可以更快地使用键,因为绕过该子树的差异。

逆天2020/03/11 11:47:36

显然情况正在发生变化。... getDerivedStateFromProps()现在是首选函数。

class Component extends React.Component {
  static getDerivedStateFromProps(props, current_state) {
    if (current_state.value !== props.value) {
      return {
        value: props.value,
        computed_prop: heavy_computation(props.value)
      }
    }
    return null
  }
}

(以上代码来自danburzo @ github)