-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
fix: replace componentWillReceiveProps by getDerivedStateFromProps and componentDidUpdate #990
Conversation
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.
@@ -290,20 +301,20 @@ export default class ReactGridLayout extends React.Component<Props, State> { | |||
this.onLayoutMaybeChanged(this.state.layout, this.props.layout); | |||
} | |||
|
|||
componentWillReceiveProps(nextProps: Props) { | |||
static getDerivedStateFromProps(nextProps: Props, prevState: State) { |
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.
There is a really big performance impact with those changes. I'm getting lag, since when we use getDerivedStateFromProps
and componentDidUpdate
it does the equality checks every single time. They're not equivalent to componentWillReceiveProps
which is only triggered when props change (not state). Not sure how we can optimize this.
Also if we go this route, we can do the changes without getDerivedStateFromProps
and just go with componentDidUpdate
(with adding a check of what changed and trigger state changes only when needed).
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.
I did some changes locally on my branch very similar to yours, but it impacts performance (maybe we can do some measurements and see how bad the impact actually is). Nevertheless, I think for such big changes it will be a good idea to involve @STRML and see what he thinks.
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.
Yeah this is problematic, this whole block is going to run many times while dragging an item. We'll need to profile & brainstorm where we can optimize.
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.
@STRML @n1ghtmare we can try this
Also if we go this route, we can do the changes without getDerivedStateFromProps and just go with componentDidUpdate
with props mirroring. It can help us to avoid extra comparisons
What do you think?
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.
We may want to require the library user to send a new layout
object (rather than mutating the existing one) or supply something optional like a layoutDidUpdate
function of arity (newLayout: Layout, oldLayout: Layout) => boolean
where the default implementation is (newLayout, oldLayout) => newLayout !== oldLayout
.
This will help us avoid an expensive deep comparison.
Perhaps some of you know a way this is handled in other libraries? I don't want to require the author to mutate key
, which will unmount all children.
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.
I think that layout recreating on the user side is not an obvious way to fix it. I mean not obvious for a user
Maybe replacing the code into componentDidMount will be enough to fix performance issues. I'll try to compare cases with componentWillReceiveProps, getDerivedStateFromProps + componentDidUpdate and 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.
@STRML Just for the sake of brainstorming (and I'm sure I'm missing something), but are we doing this comparison only for when the compactType
changes or when an item (child) is added/removed?
lib/ReactGridLayout.jsx
Outdated
@@ -85,6 +89,12 @@ export type Props = { | |||
}; | |||
// End Types | |||
|
|||
const compactType = (props: ?Object): CompactType => { |
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.
Type here is Props
, it should not be optional and it should not be Object
const { dragging } = this.state; | ||
|
||
if (!droppingPosition || !this.props.droppingPosition) { | ||
if (!droppingPosition || !prevProps.droppingPosition) { |
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.
TBH this bailout here makes this code hard to read. #980 should have refactored the droppable functionality into another function so this logic is more readable.
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.
@STRML thank you for the comment! I'll fix it right after the performance issue
a0e9ada
to
6f72052
Compare
I fixed it |
6f72052
to
25ea554
Compare
25ea554
to
729b890
Compare
Performance comparison: |
onStart={this.onDragHandler("onDragStart")} | ||
onDrag={this.onDragHandler("onDrag")} | ||
onStop={this.onDragHandler("onDragStop")} | ||
onStart={this.onDragStart} |
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.
do not recreate new functions every single render cycle
let newLayoutBase; | ||
|
||
if (prevState.activeDrag) { |
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.
do not compare layouts while dragging
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.
Dude, you've put a lot of effort in this. Great job. I love this approach. When I get some time, I'll do some testing and let you know.
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.
@n1ghtmare thank you!
729b890
to
e92c4ee
Compare
@STRML @n1ghtmare check it out, pls |
CPU usage looks good. Nice work. |
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.
Great job dude! Much appreciated.
Can you check my comment and see what you think?
lib/ReactGridLayout.jsx
Outdated
} | ||
|
||
componentDidUpdate(prevProps: Props, prevState: State) { | ||
const newLayout = this.state.layout; |
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 still triggers too many times (give it a shot with a console.log
). Do you think we can solve it by changing it to the following:
if (!this.state.activeDrag) {
const newLayout = this.state.layout;
const oldLayout = prevState.layout;
this.onLayoutMaybeChanged(newLayout, oldLayout);
}
Similar to what you're doing in the getDerivedStateFromProps
, or will this break something? I tried it locally and everything seems to be working just fine. However it should improve performance even more. What do you think?
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.
@n1ghtmare done
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.
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.
That's a nice optimization. It shouldn't break anything as the grid should only move in two circumstances:
- An active drag, or
- An update to the
layout
property from the parent.
- doesn't apply here so we should be okay 👍
componentDidUpdate - fix warnings - fix performance issues
e92c4ee
to
3d4e863
Compare
@STRML Can you please change version and push this to npm when you get the chance? |
@daynin @n1ghtmare The |
relates to: #988