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

Components: Refactor SlotFill #19242

Merged
merged 31 commits into from
Feb 26, 2020
Merged

Components: Refactor SlotFill #19242

merged 31 commits into from
Feb 26, 2020

Conversation

diegohaz
Copy link
Member

@diegohaz diegohaz commented Dec 19, 2019

Description

This PR is part of #18619.

The problem

There are several problems with the current slot-fill implementation. For example, the context value never changes because it's a class property whose value is never updated during the SlotFillProvider lifecycle:

this.contextValue = {
registerSlot: this.registerSlot,
unregisterSlot: this.unregisterSlot,
registerFill: this.registerFill,
unregisterFill: this.unregisterFill,
getSlot: this.getSlot,
getFills: this.getFills,
hasFills: this.hasFills,
subscribe: this.subscribe,
};

Because of that, both the Slot and the Fill components will never re-render when some action is done in the context (for example, when calling registerSlot or registerFill). Workarounds like forceUpdate() have been introduced to the code to overcome this:

// Sometimes the fills are registered after the initial render of slot
// But before the registerSlot call, we need to rerender the slot
this.forceUpdateSlot( name );
// If a new instance of a slot is being mounted while another with the
// same name exists, force its update _after_ the new slot has been
// assigned into the instance, such that its own rendering of children
// will be empty (the new Slot will subsume all fills for this name).
if ( previousSlot ) {
previousSlot.forceUpdate();
}

Also, the Fill component won't re-render when new fillProps are passed to the Slot component (probably, a new forceUpdate call should be placed here to work around this issue):

// If a function is passed as a child, provide it with the fillProps.
if ( isFunction( children ) ) {
children = children( slot.props.fillProps );
}

This solution

This is a rewrite of the slot-fill module using React Hooks and exposing only the Portal API (activated by using the bubblesVirtually prop today). This greatly simplifies the code without workarounds.

The component should behave exactly the same as when using the bubblesVirtually prop today, except that it will properly re-render when fillProps are updated.

The idea is to gradually migrate the codebase to use this while this is experimental and then replace the current slot-fill with this one if the experiment succeeds. This would also validate whether the current usage of slots without bubblesVirtually could use it or not.

How has this been tested?

This was tested using Storybook and unit tests.

Types of changes

New feature

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR. .

@diegohaz diegohaz mentioned this pull request Dec 19, 2019
7 tasks
@diegohaz diegohaz added [Package] Components /packages/components [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible Storybook Storybook and its stories for components labels Dec 21, 2019
@diegohaz diegohaz marked this pull request as ready for review December 21, 2019 06:01
@diegohaz diegohaz self-assigned this Dec 21, 2019
@diegohaz diegohaz added [Type] Enhancement A suggestion for improvement. and removed Storybook Storybook and its stories for components [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible labels Dec 21, 2019
@diegohaz diegohaz requested a review from gziolo January 9, 2020 22:28
@gziolo gziolo requested review from aduth and ellatrix January 13, 2020 08:38
@diegohaz diegohaz mentioned this pull request Feb 25, 2020
6 tasks
@diegohaz
Copy link
Member Author

Follow-up PR with improved tests: #20428

Copy link
Member

@gziolo gziolo left a comment

Choose a reason for hiding this comment

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

I can confirm it fixes the issue I raised yesterday. Awesome work on fixing it. I believe it closes more existing issues. I will try to identify them :)

Let's ship it 🚢

@aduth
Copy link
Member

aduth commented Mar 2, 2020

This looks really cool! I'd like to circle back and dive into the specific changes, but at least on a cursory glance, the implementation looks solid.

Would you happen to have a sense whether this will help unblock #14845 / #17355 ? I noticed some earlier comments at #17355 (comment) , but those were prior to some additional changes that came later in this pull request.

@jorgefilipecosta jorgefilipecosta added the Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Mar 16, 2020
@jorgefilipecosta jorgefilipecosta added Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta and removed Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta labels Mar 16, 2020
@jorgefilipecosta jorgefilipecosta removed the Backport to WP 6.7 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Mar 18, 2020
@draganescu
Copy link
Contributor

draganescu commented Mar 27, 2020

Advised by @aduth I tried reverting this PR and now this #18560 new editor crash is fixed. So this PR apparently did something that crashes the editor with the console message:

TypeError: "slot is undefined"

when doing this:

gif-reusable-crash

Comment on lines +29 to +32
const { [ name ]: slot, ...nextSlots } = prevSlots;
// Make sure we're not unregistering a slot registered by another element
// See https://github.com/WordPress/gutenberg/pull/19242#issuecomment-590295412
if ( slot.ref === ref ) {
Copy link
Member

Choose a reason for hiding this comment

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

Should it be safe to assume slot is defined here?

In debugging the issue mentioned by @draganescu at #18560 (comment) , the exact error occurs at this line of code:

image

It's not yet clear to me if the bug is in how the slot came to be undefined in the first place, or if we should be guarded in how we expect slot to be available at this line of code.

@jeryj jeryj mentioned this pull request Apr 10, 2023
jeryj added a commit that referenced this pull request Oct 4, 2023
…lesVirtually from the toolbar group slot

Removing bubblesVirtually from the toolbar group slot prevents any dynamically added toolbar buttons from firing their click event. This can be seen when cropping an image, you press Crop, then the Apply and Cancel buttons get added to the toolbar. Those button events don’t fire properly and is mentioned as an issue in the bubblesVirtually slot fill PR: #19242
jeryj added a commit that referenced this pull request Oct 6, 2023
…lesVirtually from the toolbar group slot

Removing bubblesVirtually from the toolbar group slot prevents any dynamically added toolbar buttons from firing their click event. This can be seen when cropping an image, you press Crop, then the Apply and Cancel buttons get added to the toolbar. Those button events don’t fire properly and is mentioned as an issue in the bubblesVirtually slot fill PR: #19242
jeryj added a commit that referenced this pull request Oct 13, 2023
…lesVirtually from the toolbar group slot

Removing bubblesVirtually from the toolbar group slot prevents any dynamically added toolbar buttons from firing their click event. This can be seen when cropping an image, you press Crop, then the Apply and Cancel buttons get added to the toolbar. Those button events don’t fire properly and is mentioned as an issue in the bubblesVirtually slot fill PR: #19242
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Components /packages/components [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants