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
The new hooks way of doing this is to use useEffect instead of componentWillReceiveProps the old way:
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 });
}
}
becomes the following in a functional hooks driven component:
// store the startTime prop in local state
const [startTime, setStartTime] = useState(props.startTime)
//
useEffect(() => {
if (props.startTime !== startTime) {
setStartTime(props.startTime);
}
}, [props.startTime]);
we set the state using setState, using useEffect we check for changes to the specified prop, and take the action to update the state on change of the prop.
// store the startTime prop in local state
const [startTime, setStartTime] = useState(props.startTime)
//
useEffect(() => {
if (props.startTime !== startTime) {
setStartTime(props.startTime);
}
}, [props.startTime]);
Can this method be migrated to class components?
You Probably Don't Need Derived State
1. Set a key from the parent
When a key changes, React will create a new component instance rather than update the current one. Keys are usually used for dynamic lists but are also useful here.
2. Use getDerivedStateFromProps
/ componentWillReceiveProps
If key doesn’t work for some reason (perhaps the component is very expensive to initialize)
By using getDerivedStateFromProps
you can reset any part of state but it seems
a little buggy at this time (v16.7)!, see the link above for the usage
It's quite clearly from their docs:
If you used componentWillReceiveProps for re-computing some data only when a prop changes, use a memoization helper instead.
Use: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#what-about-memoization
componentWillReceiveProps
is being deprecated because using it "often leads to bugs and inconsistencies".
If something changes from the outside, consider resetting the child component entirely with key.
Providing a key
prop to the child component makes sure that whenever the value of key
changes from the outside, this component is re-rendered. E.g.,
<EmailInput
defaultEmail={this.props.user.email}
key={this.props.user.id}
/>
On its performance:
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.
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 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.
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 });
}
}