-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor willReceiveProps usages into getDerivedStateFromProps #129
Refactor willReceiveProps usages into getDerivedStateFromProps #129
Conversation
Thanks @tstirrat15! I completely agree on the motivation. We must get rid of these deprecated lifecycle functions before the next major version comes out. Let me try your version tomorrow. I want to check if it works when used as a "controlled" component. I mean, when another component takes over control of the rating value. BTW: |
src/RatingAPILayer.js
Outdated
this.setState({ | ||
value: nextProps.initialRating | ||
}); | ||
componentWillUpdate(prevProps) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is not componentWillUpdate
deprecated? Did you mean componentDidUpdate
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤦♂️ yes, you're right. I'll tweak that.
There we go. |
Don't worry... Test are a little messy right now. They need a good cleaning 😓 |
It's weird but the reset example only works the first time you reset the rating. If you select again after it was reset, then it does not work anymore. The reset example is a use case of what I like to call "controlled" component behavior. The state value is overriden by the props attribute. |
The behavior you're describing looks consistent with the way it's written. class ResetRating extends React.Component {
constructor(props) {
super(props);
this.state = {value: 0};
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
this.setState({value: undefined});
}
render() {
return (
<div>
<Rating {...this.props} initialRating={this.state.value} />
<button onClick={this.handleClick}>Reset</button>
</div>
);
}
} When you click the button the first time, the I guess it might be different from the previous behavior because |
This component can be used as an uncontrolled component (the state is managed internally) or as a controlled component (the state is controlled through props by a parent component). As an example, I would like to be able to keep the value updated by a parent/wrapper component like this: class InputRating extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 1
};
this.handleChangeInput = this.handleChangeInput.bind(this);
this.handleChangeRating = this.handleChangeRating.bind(this);
}
handleChangeInput(event) {
this.setState({ value: event.target.value });
}
handleChangeRating(value) {
this.setState({ value });
}
render() {
return (
<div>
<p>
<input
type="range"
min={1}
max={5}
value={this.state.value}
onChange={this.handleChangeInput}
/>
</p>
<Rating
initialRating={this.state.value}
onChange={this.handleChangeRating}
/>
</div>
);
}
} Check this example on codesandbox. You can change the rating value either using the actual rating component or the slider. Both components, input and rating components, are being used as controlled components. Maybe getDerivedStateFromProps is the solution. BTW: |
Have a look now. I agree with other commenters that If a user wants to create an uncontrolled component using a controlled component as the base, it's not terribly difficult to write your own wrapper. |
I agree with both the misleading name and the controlled component to be reexamined in a future version. In fact, I think it is part of how this library has evolved. It started as a closed uncontrolled component where you set the Maybe having |
src/RatingAPILayer.js
Outdated
value: nextProps.initialRating | ||
}); | ||
static getDerivedStateFromProps(props, prevState) { | ||
const { initialRating } = this.props; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ups. this.props
-> props
So used to write always together...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤦♂️ good catch.
Yeah, I agree. I think you wouldn't even need a I think you'd still need the internal state layer of |
If you're interested, I could create an issue/PR for moving towards a controlled component API. |
I have been reading about it. In You Probably Don't Need Derived State it is mentioned as anti-pattern the way it was/is the I would be really open to accept a PR 👍. |
Sounds good. I'll put that on my TODO list. |
Motivation
Pull #128 fixed the warnings around
willReceiveProps
, but it did so by essentially silencing them. Given thatwillReceiveProps
is deprecated, it'd be better to move to a different approach. This puts that logic indidUpdate
, which is a better place for it.Changes
willReceiveProps
todidUpdate
Testing
See that the hover, click and reset functionality in the "Reset Rating" example in
index.html
still work.Note
I had a couple of tests failing, but they were also failing on master. Not quite sure what was going on there.