-
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
Experiment: Client-side navigation of the Query Loop block using directives #44034
Conversation
I've added a few things:
|
The prefetch and the cache are working perfectly now ✅ I've switched to vnode-based hooks for the WordPress Directives. It's still low level and I didn't change the internal Preact names ( // The `wp-client-navigation` directive.
wpDirectives.clientNavigation = {
onDiff: ({ props }) => {
const {
wp: { clientNavigation },
href,
} = props;
// Prefetch the page if it is in the directive options.
if (clientNavigation?.prefetch) {
fetchPage(href);
}
// Don't do anything if it's falsy.
if (!!clientNavigation) {
props.onclick = async (event) => {
event.preventDefault();
// Fetch the page (or return it from cache).
const vdom = await fetchPage(href);
// Render the new page.
render(vdom, rootFragment);
// Update the URL.
window.history.pushState({}, "", href);
// Update the scroll, depending on the option. True by default.
if (clientNavigation?.scroll === "smooth") {
window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
} else if (clientNavigation?.scroll !== false) {
window.scrollTo(0, 0);
}
};
}
},
}; I want to try wrapping the vnode with a component to be able to use I left a I've also added an animation to make sure that Preact is never removing DOM nodes when hydrating (or rehydrating). |
Ok, this feels much better now. You can even use regular hooks. // The `wp-client-navigation` directive.
directive("clientNavigation", (props) => {
const { wp: { clientNavigation }, href } = props;
useEffect(() => {
// Prefetch the page if it is in the directive options.
if (clientNavigation?.prefetch) {
prefetch(href);
}
});
// Don't do anything if it's falsy.
if (!!clientNavigation) {
props.onclick = async (event) => {
event.preventDefault();
// Fetch the page (or return it from cache).
await navigate(href);
// Update the URL.
window.history.pushState({}, "", href);
// Update the scroll, depending on the option. True by default.
if (clientNavigation?.scroll === "smooth") {
window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
} else if (clientNavigation?.scroll !== false) {
window.scrollTo(0, 0);
}
};
}
}); Remember, once it is defined, just need to add the directive to the HTML (in PHP or in the <a wp-client-navigation href="/some-post">Some post</a> We need to figure out the use cases that we need to cover to see if this API fits well or if we need to add more things (i.e., a I've also refactored a bit the code into different files: |
I've started another client-side navigation experiment for WooCommerce's Product Query block. This one is replacing only the inner children of the Product Query block instead of the whole document. |
For context: I took a look at the |
Superseded by #53812. |
What?
This is an experiment to implement client-side navigations in the Query Loop block.
It's an alternative to #38713 based on our experiments with Directives hydration.
Why?
To be able to implement patterns that improve the user experience.
How?
It fetches the HTML of the next page and diffs the DOMs using Preact's virtual DOM.
This is just a quick experiment. @DAreRodz and I are working on an implementation of this algorithm that can also hydrate interactive components:
It's also worth noting that this approach can work for any page navigation, not only those of the Query Loop block.
Testing Instructions
Create a post or page with a Query Loop and navigate using the Next or Previous buttons.
As long as the next/previous links are preserved in the DOM, the vDOM diffing is intelligent enough not to destroy them, and the event handlers keep working. But on the first and last page, the links disappear from the DOM and lose the event handler. I haven't done anything to reattach the event listeners because I want to test using directives instead.EDIT: This is working fine after we switched to directives.
Screenshots or screencast
Screen.Capture.on.2022-09-09.at.16-40-32.mp4
Next steps
I'll probably use this to test more patterns: