-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Refactor Nav creation hooks and associated code #38824
Conversation
@@ -495,6 +528,13 @@ function Navigation( { | |||
setRef( id ); | |||
onClose(); | |||
} } | |||
onSelectClassicMenu={ ( menu ) => { | |||
onClose(); |
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.
Calling onClose
here allows the dropdown to close and the block UI to update whilst the async conversion process happens.
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.
Need to be a little careful about focus management here.
@@ -495,6 +528,13 @@ function Navigation( { | |||
setRef( id ); | |||
onClose(); | |||
} } | |||
onSelectClassicMenu={ ( menu ) => { | |||
onClose(); | |||
convertClassicMenuToBlocks( |
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.
By passing the conversion code down into the dropdown we avoid errors thrown when the dropdown unmounts and an async request triggered by that component resolves. We do this by handling in the parent (which is not unmounted when the option is clicked).
@@ -676,6 +716,7 @@ function Navigation( { | |||
/> | |||
) } | |||
{ ! hasResolvedCanUserCreateNavigation || | |||
isResolvingClassicMenuConversion || | |||
( ! isEntityAvailable && ! isPlaceholderShown && ( | |||
<PlaceholderPreview isLoading /> |
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 need to look again at loading states because I don't yet see this. Perhaps because of the call to await createNavigationMenu
(which again has no resolution status indicators).
@@ -55,4 +59,12 @@ export default function useConvertClassicMenu( onFinish ) { | |||
}, | |||
[ hasResolvedMenuItems, createFromMenu ] | |||
); | |||
|
|||
return { | |||
dispatch, |
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 don't love dispatch here. We could use run
or similar?
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.
convert
?
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.
Dropping an early review, though I realise this is still a draft.
I'm pretty familiar with this code as I had to write this last minute patch for 5.9 - #38168.
I didn't do anything drastic in that PR, but it did introduce the useConvertClassicMenu
hook, which to be honest, I don't love. It was just moving the existing code into something reusable rather than improving the code quality.
IMO, I think we should probably explore more drastic changes than we do in this PR and instead try to get rid of useConvertClassicMenu
.
Here's what I think is the problem. Hooks that work with or return data are generally 'long lived', they'll be active for entire lifecycle of a component. Converting a menu though is a one-time action that doesn't require data to be kept around.
There are two bits of data that useConvertClassicMenu
persists when it doesn't need to - the classic menu name, and the classic menu items (which it fetches once it has a menu id). I think that's problematic, because what are we supposed to do with this data after a conversion has happened? We could reset it, but then we're just doing garbage collection manually.
Another option is to instead make classic menu conversion a normal async function instead of a hook. Give the function a menu id, it maybe calls apiFetch
instead of useSelect
to get the menu items and returns blocks. The only thing we lose is caching of the classic menu items in the store, but I don't think classic menu conversion is a common or regular interaction so it's an ok trade-off.
It may also be good to get some design input into the loading states. I don't know how we can adequately convey that clicking a classic menu is an asynchronous operation.
@@ -55,4 +59,12 @@ export default function useConvertClassicMenu( onFinish ) { | |||
}, | |||
[ hasResolvedMenuItems, createFromMenu ] | |||
); | |||
|
|||
return { | |||
dispatch, |
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.
convert
?
const { | ||
dispatch: convertClassicMenuToBlocks, | ||
blocks: classicMenuBlocks, | ||
name: classicMenuName, | ||
isResolving: isResolvingClassicMenuConversion, | ||
hasResolved: hasResolvedClassicMenuConversion, | ||
} = useConvertClassicMenu(); |
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.
It seems like a lot of overhead to run this on every render of edit
when converting classic menus is a rare interaction for the user. It'll result in the block always fetching all classic menus.
if ( | ||
hasResolvedClassicMenuConversion && | ||
classicMenuName && | ||
classicMenuBlocks?.length |
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.
If I have an empty classic menu, nothing happens when clicking the menu item. (it's the first thing I noticed when testing as all my classic test menus are empty 😄 )
@@ -495,6 +528,13 @@ function Navigation( { | |||
setRef( id ); | |||
onClose(); | |||
} } | |||
onSelectClassicMenu={ ( menu ) => { | |||
onClose(); |
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.
Need to be a little careful about focus management here.
hasResolvedClassicMenuConversion, | ||
] ); | ||
|
||
const isStillLoading = |
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 know this was already in trunk
, but I think a good improvement would be a rename of this variable:
const isStillLoading = | |
const isLoading = |
TBH I've been going round and round with this trying to decide what to do. I thought I'd push this up and at least then it would be easier to discuss. Glad you 👀 and left thoughts - thank you. Let's consider the more drastic changes you suggest. I am keen that we are able to convey when something is "working" so we'll need to keep that in mind. |
For what it's worth I don't think we can or should attempt to do this within the dropdown / menu item itself. Instead we
The block shouldn't care how the data is being loaded. All it needs to know is that the data isn't available and thus it should be in a "loading" state. |
We can lean on const registry = useRegistry();
const callback = useCallback(() => {
setIsConverting( true );
try{
await convertClassicMenu( registry );
showSuccessNotice();
} catch(e) {
showErrorNotice(e);
} finally {
setIsConverting( false );
}
}, [registry]) and then we can do things like |
😮 Thanks Adam! I have another PR where I've changed course to use "one big async function". I'll push that up and then post a link here so we can discuss if/how to migrate over to using registry and friends as @adamziel suggests. |
Closing in favour of #38858 |
Description
Continues work on #37190.
This PR looks to address the inconsistencies around the code paths (especially hooks) around the creation of classic menus into block based menus.
Currently many of the hooks involved are very opaque and despite being async, provide little or not information about the resolution status of the async requests involved. This causes UI issues such as that which is experienced when selecting a classic menu from the dropdown and observing how the UI appears "locked" whilst the async request resolves.
This PR takes a step towards solving these problems. Principally it exposes information about the resolution status of the
useConvertClassicMenu
hook which allows the UI to respond according.Testing Instructions
Screenshots
Types of changes
Checklist:
*.native.js
files for terms that need renaming or removal).