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

Fix RichText rerendering when it shouldn't #12161

Merged
merged 3 commits into from
Nov 21, 2018

Conversation

atimmer
Copy link
Member

@atimmer atimmer commented Nov 21, 2018

closes #12150

Description

The prepareEditableTree and onChangeEditableValue function stacks would have a new reference on every render. This prevents that by memoized the stack based on the previous stack and the newly added function.

How has this been tested?

Tested using Yoast SEO. I am working on e2e tests to test that RichText's doesn't rerender too often.

Screenshots

Types of changes

Checklist:

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

The prepareEditableTree and onChangeEditableValue function stacks
would have a new reference on every render. This prevents that by
memoized the stack based on the previous stack and the newly added
function.
*
* @return {Object} The annotations props object.
*/
const getAnnotationObject = memize( ( annotations ) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of memoizing function, I think it would be better for the registerFormatType function to do the memoization itself using a shallow comparison. This way it would work with any implementation of __experimentalGetPropsForEditableTreePreparation

That said, we're kind of running out of time, so I'm not considering this as blocking at the moment as it's a forward-compatible change.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed, this sounds better.

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

I confirm that this does fix the Yoast incompatibility issue.

@youknowriad youknowriad added this to the 4.5.1 milestone Nov 21, 2018
@@ -4,6 +4,8 @@
import createSelector from 'rememo';
import { get, flatMap } from 'lodash';

const emptyArray = [];
Copy link
Member

Choose a reason for hiding this comment

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

Minor: I think in other places we called this EMPTY_ARRAY.

Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't be bad to have the same comment:

/**
* Shared reference to an empty array for cases where it is important to avoid
* returning a new array reference on every invocation, as in a connected or
* other pure component which performs `shouldComponentUpdate` check on props.
* This should be used as a last resort, since the normalized data should be
* maintained by the reducer result in state.
*
* @type {Array}
*/
const EMPTY_ARRAY = [];

Copy link
Member

Choose a reason for hiding this comment

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

Minor: I think in other places we called this EMPTY_ARRAY.

Related guideline: https://github.com/WordPress/gutenberg/blob/master/docs/contributors/coding-guidelines.md#constants

@@ -119,6 +120,14 @@ export function registerFormatType( name, settings ) {

dispatch( 'core/rich-text' ).addFormatTypes( settings );

const emptyArray = [];
const getFunctionStackMemoized = memize( ( previousStack = emptyArray, newFunction ) => {
Copy link
Member

Choose a reason for hiding this comment

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

Would it work to keep the cache size to one?

Copy link
Member

Choose a reason for hiding this comment

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

Also, why do both this and prepareEditableTree need to be memoized? Could use some more clarification.

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably not as we need one per RichText I think.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think so, because a different function could be returned based on richTextIdentifier/blockClientId.

Copy link
Member

Choose a reason for hiding this comment

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

Just wondering because it's probably best to keep cache size as small as possible. I'm guessing the issue is just consecutive calls and nothing else.

Copy link
Member

Choose a reason for hiding this comment

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

So how big is this cache going to grow?

Copy link
Member

Choose a reason for hiding this comment

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

No way to cache per instance?

Copy link
Contributor

Choose a reason for hiding this comment

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

That's a good question though

@@ -119,6 +120,14 @@ export function registerFormatType( name, settings ) {

dispatch( 'core/rich-text' ).addFormatTypes( settings );

const emptyArray = [];
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

@ellatrix
Copy link
Member

Just wondering, does this also fix #11595 (comment)?

@atimmer atimmer force-pushed the fix/optimize-rich-text-rerenders branch from 8ba55a9 to 2fc48e9 Compare November 21, 2018 09:39
@youknowriad
Copy link
Contributor

@iseulde In my testing it doesn't fix it completely

@atimmer
Copy link
Member Author

atimmer commented Nov 21, 2018

That is what I concluded too. It's probably not far away. I will dive into that further to completely fix it. But I thought that doesn't have to be in 4.5.1.

/**
* External dependencies
*/
import memize from 'memize';
Copy link
Member

Choose a reason for hiding this comment

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

I don't see this added as a dependency.

@@ -26,6 +26,7 @@
"@wordpress/i18n": "file:../i18n",
"@wordpress/rich-text": "file:../rich-text",
"lodash": "^4.17.10",
"memize": "^1.0.5",
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 we also need it on the server side.

Copy link
Contributor

Choose a reason for hiding this comment

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

No we don't, there's no script for memize

Copy link
Member

Choose a reason for hiding this comment

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

Oh, cool then :)

@youknowriad youknowriad merged commit 01be7ac into master Nov 21, 2018
@youknowriad youknowriad deleted the fix/optimize-rich-text-rerenders branch November 21, 2018 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Annotations Adding annotation functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Browser gets frozen after pressing ENTER button
6 participants