开发者问题收集

在 React Form 中根据 props 的改变更新状态

2015-09-05
383934

我在使用 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 reached 错误。

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

当前代码:

@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
3个回答

componentWillReceiveProps is depcricated since react 16: use getDerivedStateFromProps instead

如果我理解正确的话,您有一个父组件,它将 start_time 传递给 ModalBody 组件,并将其分配给自己的状态?并且你想从父组件而不是子组件更新该时间。

React 有一些关于处理这种情况的提示。 (请注意,这是一篇旧文章,现已从网络上删除。以下是当前 有关组件 props 的文档 的链接)。

Using props to generate state in getInitialState often leads to duplication of "source of truth", i.e. where the real data is. This is because getInitialState is only invoked when the component is first created.

Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble.

基本上,每当你将父级的 props 分配给子级的 state 时,在 prop 更新时并不总是调用 render 方法。您必须使用 componentWillReceiveProps 方法手动调用它。

componentWillReceiveProps(nextProps) {
  // You don't have to do this check first, but it can help prevent an unneeded render
  if (nextProps.startTime !== this.state.startTime) {
    this.setState({ startTime: nextProps.startTime });
  }
}
BradByte
2015-09-05

显然事情正在发生变化.... 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 提供)

ErichBSchulz
2018-04-17

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

如果外部发生了变化,请考虑使用 key 完全重置子组件。

向子组件提供 key prop 可确保每当 key 的值从外部发生变化时,此组件都会重新渲染。例如,

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

关于其性能:

While this may sound slow, the performance difference is usually insignificant. Using a key can even be faster if the components have heavy logic that runs on updates since diffing gets bypassed for that subtree.

Lucia
2018-11-15