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

Block Editor: Reimplement BlockEditorProvider using hooks #16357

Closed
wants to merge 1 commit into from

Conversation

aduth
Copy link
Member

@aduth aduth commented Jun 28, 2019

This pull request seeks to refactor the BlockEditorProvider component to use React hooks in order to sync blocks value as effects leveraging existing data hooks for value subscriptions.

The hope with this change was to simplify the logic flow, but I'd also hoped for some performance optimization to come from this simplification. However, it doesn't appear to have any benefit and in-fact has a minor negative impact (~106ms to 109ms average time to type via npm run test-performance). It's unclear to me why this would be the case. While I've not dug into it, I'm curious if useSelect is as performance-optimized as it can be in cases where a component renders for reasons other than state changes (i.e. does it call the mapping selector even though state hasn't changed?).

If the performance degradation cannot be resolved, I'm not sure whether it's worth moving forward with these changes.

If we do move forward with these changes, I think we could explore further flattening to reimplement the internal withRegistryProvider higher-order component as a hook.

Testing Instructions:

Verify there are no regressions in standard usage (particularly via blocks updates, reusable blocks, etc).

@aduth aduth added [Type] Performance Related to performance efforts [Type] Code Quality Issues or PRs that relate to code quality [Package] Block editor /packages/block-editor labels Jun 28, 2019
@aduth aduth requested a review from youknowriad June 28, 2019 21:00
Comment on lines +16 to +17
onChange = () => {},
onInput = () => {},
Copy link
Member

Choose a reason for hiding this comment

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

Microoptimization: Instead of creating 2 separate functions these could both reference a dummy empty function.

Copy link
Member

Choose a reason for hiding this comment

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

Specifically, the noop function provided by Lodash could be used here.

Comment on lines +25 to +37
const { blocks, isPersistent, isIgnored } = useSelect( ( select ) => {
const {
getBlocks,
isLastBlockChangePersistent,
__unstableIsLastBlockChangeIgnored,
} = registry.select( 'core/block-editor' );
} = select( 'core/block-editor' );

let blocks = getBlocks();
let isPersistent = isLastBlockChangePersistent();

this.unsubscribe = registry.subscribe( () => {
const {
onChange,
onInput,
} = this.props;
const newBlocks = getBlocks();
const newIsPersistent = isLastBlockChangePersistent();
if (
newBlocks !== blocks && (
this.isSyncingIncomingValue ||
__unstableIsLastBlockChangeIgnored()
)
) {
this.isSyncingIncomingValue = false;
blocks = newBlocks;
isPersistent = newIsPersistent;
return;
return {
blocks: getBlocks(),
isPersistent: isLastBlockChangePersistent(),
isIgnored: __unstableIsLastBlockChangeIgnored(),
};
} );
Copy link
Member

Choose a reason for hiding this comment

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

A big optimization that could be made here is adding an empty dependency array to this useSelect.

};
} );

const previousBlocks = useRef( blocks );
Copy link
Member

Choose a reason for hiding this comment

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

This looks like a use-case for a usePrevious hook. I'm actually using one already in #21181, and I wonder if we should add it to @wordpress/compose.

Copy link
Member

Choose a reason for hiding this comment

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

usePrevious has now been added to the @wordpress/compose package, so it could definitely be used here.

Comment on lines +4 to +5
import { useEffect, useRef } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: I think imports should be in alphabetical order.

Suggested change
import { useEffect, useRef } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { useDispatch, useSelect } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';

@noahtallen
Copy link
Member

I converted the block editor provider to use hooks in #21368. This PR could probably be changed to introduce any performance optimizations suggested?

@ZebulanStanphill
Copy link
Member

Thanks for pointing that out, @noahtallen. I've opened #23255 to add missing dependency arrays to useSelect calls throughout the codebase.

Seeing as that the original purpose of this PR has already been fulfilled by another PR, I'm closing this one. Thanks for making this PR, @aduth, even if it didn't end up being used in the end. ❤️

@youknowriad youknowriad deleted the update/block-editor-provider-hooks branch June 18, 2020 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Block editor /packages/block-editor [Type] Code Quality Issues or PRs that relate to code quality [Type] Performance Related to performance efforts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants