-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
FocalPointPicker: Supply default value as initial percentages state to fix NaN warning #15400
Conversation
@@ -27,7 +27,7 @@ export class FocalPointPicker extends Component { | |||
this.state = { | |||
isDragging: false, | |||
bounds: {}, | |||
percentages: {}, | |||
percentages: FocalPointPicker.defaultProps.value, |
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.
It's neither here nor there to the specific fix, but this looks to me like a classic violation of a previously-documented anti-pattern:
@@ -27,7 +27,7 @@ export class FocalPointPicker extends Component { | |||
this.state = { | |||
isDragging: false, | |||
bounds: {}, | |||
percentages: {}, | |||
percentages: FocalPointPicker.defaultProps.value, |
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.
To the specific fix however: It's terribly confusing to me that we assign this value and immediately override it in componentDidMount
with a setState
.
I think this should just be changed to props.value
(props
being the first argument of the constructor
) and eliminate componentDidMount
altogether. Otherwise, we're completely disregarding value
from the props
for the initial (albeit ultimately wasteful) render.
You may call setState() immediately in componentDidMount(). It will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state. Use this pattern with caution because it often causes performance issues. In most cases, you should be able to assign the initial state in the constructor() instead. It can, however, be necessary for cases like modals and tooltips when you need to measure a DOM node before rendering something that depends on its size or position.
https://reactjs.org/docs/react-component.html#componentdidmount
(Emphasis mine)
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.
Done in 9b1b029
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.
This looks good to me and tests just fine. Thinking back, I believe I set the percentages in componentDidMount
because of an earlier approach to determining the image's dimensions, which I moved away from before submitting the initial Pull Request. Agree with @westonruter it's not necessary.
The
FocalPointPicker
component can result in a React warning being emitted from the console:The reason for this that the
state
for the component has an emptypercentages
by default:gutenberg/packages/components/src/focal-point-picker/index.js
Line 30 in 77b8234
Because of this
percentages.x
is initiallyundefined
and in this code:gutenberg/packages/components/src/focal-point-picker/index.js
Line 220 in 77b8234
The
this.fractionToPercentage( percentages.x )
call will returnNaN
.The fix seems to be as simple as using the default prop
value
as the initial state forpercentages
.Fixes #15136.