在 React Form 中根据 props 的改变更新状态
我在使用 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
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 becausegetInitialState
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 });
}
}
显然事情正在发生变化.... 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
}
}
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.