Skip to content
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

Editor: Make sure createInnerBlockList never updates when passed using context #6420

Merged
merged 1 commit into from
May 2, 2018

Conversation

gziolo
Copy link
Member

@gziolo gziolo commented Apr 25, 2018

Description

When working on another PR I discovered that createInnerBlockList passed through context to BlockEdit trigger tons of rerenders. This PR tries to fix it.

I included also shouldComponentUpdate( nextProps, nextState ) method inside BlockEdit component in 909844f commit. It is bundled with debugging tools by design, because it should be fixed with another PR which @youknowriad is working on: #6313. In effect, this PR depends on #6313 and shouldn't be merged before we confirm that pure HOC resolves all re-renders when props and state don't change.

How has this been tested?

In the browser using some debugging hacks on the JS console. I included them in the PR with
909844f. It must be removed before this branch gets merged :)

In general, we need to make sure that there is no regression introduced in all blocks, in particular, nested blocks should be examined very carefully.

Screenshots

Before

createinnerblock

After

blockedit render after

Types of changes

Performance improvements.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.

@gziolo gziolo added [Type] Enhancement A suggestion for improvement. [Type] Performance Related to performance efforts labels Apr 25, 2018
@gziolo gziolo added this to the 2.8 milestone Apr 25, 2018
@gziolo gziolo self-assigned this Apr 25, 2018
@@ -96,10 +102,7 @@ export class BlockListBlock extends Component {
// is defined in `@wordpress/blocks`, so to avoid a circular dependency
// we inject this function via context.
return {
createInnerBlockList: ( uid ) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it may have been expected that getChildContext wasn't called as frequently as it actually is. While this works, an alternative may be to simply update this to the React 16.3.0 syntax. In either case, we should want the function to point to a consistent reference (the legacy API may actually make this easier for object context).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Playing with when "context creators" are called: https://codepen.io/aduth/pen/LmZgKN?editors=1111

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://codepen.io/anon/pen/vjXXOa?editors=1111 - when you add similar console.log calls for the new context, there is no difference in the way they re-render. There might be something I'm missing in here.

Anyways, I think that in the long createInnerBlockList could be used directly as a dependency without using context at all. We would have to move components from wp.blocks to wp.editor and apply a few more refactorings.

Should we apply this PR as a short-term solution and explore optimizing modules structure to remove obsolete usage of context?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyways, I think that in the long createInnerBlockList could be used directly as a dependency without using context at all.

I'm curious how you'd see this working. Do you mean being explicit with how a block must pass its own rootUID? The existence of this context is largely to simplify the implementation behavior for block authors (similar in many ways to the auto-handling of isSelected).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be easier to reason after Framework: Move components from the blocks to the editor module (#6521) gets merged. It seems like you would be able to use createInnerBlockList as an internal function, but you would still have to pass down renderBlockMenu. I would investigate once all blocks components are moved to editor.

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we apply this PR as a short-term solution and explore optimizing modules structure to remove obsolete usage of context?

Yes, I think we should look to get this in more-or-less as-is. Can you remove the debugging changes?

@@ -50,7 +52,26 @@ export class BlockEdit extends Component {
};
}

componentDidUpdate( prevProps, prevState ) {
const notEqual = ! isShallowEqual( prevProps, this.props );
console.log( 'BlockEdit did update:', notEqual, ! isShallowEqual( prevState, this.state ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming we should drop these debugging changes (i.e. all of the changes to this file)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have a separate commit to remove from this PR with debug only.

@@ -96,10 +102,7 @@ export class BlockListBlock extends Component {
// is defined in `@wordpress/blocks`, so to avoid a circular dependency
// we inject this function via context.
return {
createInnerBlockList: ( uid ) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyways, I think that in the long createInnerBlockList could be used directly as a dependency without using context at all.

I'm curious how you'd see this working. Do you mean being explicit with how a block must pass its own rootUID? The existence of this context is largely to simplify the implementation behavior for block authors (similar in many ways to the auto-handling of isSelected).

@gziolo gziolo force-pushed the fix/crate-inner-block-list branch from b64b5d5 to 734f28a Compare May 2, 2018 11:35
@gziolo
Copy link
Member Author

gziolo commented May 2, 2018

Yes, I think we should look to get this in more-or-less as-is. Can you remove the debugging changes?

Debug changes were removed.

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

@gziolo gziolo merged commit 9a9d435 into master May 2, 2018
@gziolo gziolo deleted the fix/crate-inner-block-list branch May 2, 2018 12:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Enhancement A suggestion for improvement. [Type] Performance Related to performance efforts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants