HiveBrain v1.2.0
Get Started
← Back to all entries
patternreactCritical

Updating state on props change in React Form

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
propsupdatingreactchangestateform

Problem

I am having trouble with a React form and managing the state properly. I have a time input field in a form (in a modal). The initial value is set as a state variable in getInitialState, and is passed in from a parent component. This in itself works fine.

The problem comes when I want to update the default start_time value through the parent component. The update itself happens in the parent component through setState start_time: new_time. However in my form, the default start_time value never changes, since it is only defined once in getInitialState.

I have tried to use componentWillUpdate to force a change in state through setState start_time: next_props.start_time, which did actually work, but it gave me Uncaught RangeError: Maximum call stack size exceeded errors.

So my question is, what's the correct way of updating state in this case? Am I thinking about this wrong somehow?

Current Code:

```
@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:

Solution

componentWillReceiveProps is depcricated since react 16: use getDerivedStateFromProps instead

If I understand correctly, you have a parent component that is passing start_time down to the ModalBody component which assigns it to its own state? And you want to update that time from the parent, not a child component.

React has some tips on dealing with this scenario. (Note, this is an old article that has since been removed from the web. Here's a link to the current doc on component 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.

Basically, whenever you assign parent's props to a child's state the render method isn't always called on prop update. You have to invoke it manually, using the componentWillReceiveProps method.

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 });
  }
}

Code Snippets

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 });
  }
}

Context

Stack Overflow Q#32414308, score: 317

Revisions (0)

No revisions yet.