Skip to content
This repository has been archived by the owner on Oct 16, 2024. It is now read-only.

Fix preview width when searching or filtering patterns #115

Merged
merged 9 commits into from
Mar 15, 2023

Conversation

mike-day
Copy link
Contributor

@mike-day mike-day commented Mar 14, 2023

Related to the work in #109 and #95 — preview widths are sometimes stale when filtering by clicking category options or searching in the patterns view:

pm-preview-sizing-issue

The width expands when it is the only filtered option, but remains at full-width when it should be resized to accommodate a second result.


This PR expands on and replaces the useWindowSize hook in #109 to allow other dependencies (such as filteredPatterns/themePatterns) to also trigger a re-render:

pm-preview-sizing-fix

Now, regardless of how the user searches, clicks through categories, or resizes the window, we can also be sure a fresh grid of pattern previews with correct dimensions is displayed.


How to test

  1. Checkout the branch
  2. Filter the patterns by searching and/or clicking various categories
  3. Resize your browser window
  4. The previews should remain at the expected scale throughout

Notes

Not that this was expected to change, but even with the extra rendering introduced by these changes, Lighthouse scores remain screaming fast. Care was taken to ensure this does not cause an unneeded re-render on initial load:

Screenshot 2023-03-14 at 3 13 50 PM

// Helps ensure PatternPreview iFrames are the right size.
useWindowResize();
useForceRerend( [ themePatterns ] );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The main problem relates to not being certain we are getting the correct BoundingClientRect (and thus scale) in PatternPreview, even when new categories are filtered.

This was the simplest way I could think of to be absolutely sure all previews in the grid are freshly rendered with the correct BoundingClientRect while using a derived state for previewContainerSize.


The patterns passed via themePatterns are filtered by search term or selected category, so we can use it instead of passing any new props.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good way to force rerendering when the filtered patterns change.

Comment on lines 10 to 12
export default function useForceRerend< T extends unknown >(
dependencies: T[] = []
) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it is okay to allow pretty much any type of value in the dependencies array.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, useForceRerend() is agnostic to the component that calls it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactoring my solution from yesterday here 🤣

Copy link
Contributor

@kienstra kienstra Mar 14, 2023

Choose a reason for hiding this comment

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

Sounds good, it's always good to look back and improve things

Comment on lines 17 to 22
// Do not cause a re-render on first render.
if ( initialRender.current ) {
initialRender.current = false;
} else {
setForceUpdate( dependencies );
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This setForceUpdate() should only run when dependencies are updated.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you see a performance boost compared to not using the if guard clause?

diff --git a/wp-modules/app/js/src/hooks/useForceRerend.ts b/wp-modules/app/js/src/hooks/useForceRerend.ts
index b8655ffc..59db5d80 100644
--- a/wp-modules/app/js/src/hooks/useForceRerend.ts
+++ b/wp-modules/app/js/src/hooks/useForceRerend.ts
@@ -11,21 +11,12 @@ export default function useForceRerend< T extends unknown >(
        dependencies: T[] = []
 ) {
        const [ , setForceUpdate ] = useState< T[] | WindowDimensions >();
-       const initialRender = useRef( true );
 
        useLayoutEffect( () => {
-               // Do not cause a re-render on first render.
-               if ( initialRender.current ) {
-                       initialRender.current = false;
-               } else {
-                       setForceUpdate( dependencies );
-               }
+               setForceUpdate( dependencies );

Copy link
Contributor

@kienstra kienstra Mar 14, 2023

Choose a reason for hiding this comment

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

I'd vote to keep this if/else only if it adds a big performance boost.

Otherwise, simply calling setForceUpdate( dependencies ); might be fine.

Copy link
Contributor Author

@mike-day mike-day Mar 15, 2023

Choose a reason for hiding this comment

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

In testing, it does not really improve performance in any meaningful way (especially considering that we are potentially get just one additional state update on initial render — it's a non-issue right now).

That block and ref were removed in 0884c93!

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, 0884c93 looks really good.

Copy link
Contributor

@kienstra kienstra left a comment

Choose a reason for hiding this comment

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

Hi @mike-day,
Nice work! A few implementation comments below, but this is a nice improvement.

@kienstra
Copy link
Contributor

Looks like my comments didn't show up in the review. Adding some now.

Copy link
Contributor

@kienstra kienstra left a comment

Choose a reason for hiding this comment

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

Here are the comments I meant to leave before

wp-modules/app/js/src/hooks/useForceRerend.ts Outdated Show resolved Hide resolved
wp-modules/app/js/src/hooks/useForceRerend.ts Outdated Show resolved Hide resolved
// Helps ensure PatternPreview iFrames are the right size.
useWindowResize();
useForceRerend( [ themePatterns ] );
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good way to force rerendering when the filtered patterns change.

wp-modules/app/js/src/hooks/useForceRerend.ts Outdated Show resolved Hide resolved
Comment on lines 17 to 22
// Do not cause a re-render on first render.
if ( initialRender.current ) {
initialRender.current = false;
} else {
setForceUpdate( dependencies );
}
Copy link
Contributor

@kienstra kienstra Mar 14, 2023

Choose a reason for hiding this comment

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

I'd vote to keep this if/else only if it adds a big performance boost.

Otherwise, simply calling setForceUpdate( dependencies ); might be fine.

Copy link
Contributor

@kienstra kienstra Mar 14, 2023

Choose a reason for hiding this comment

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

Sounds good, it's always good to look back and improve things

/**
* Re-render the calling component when the window is resized.
*
* Optionally include an array of dependencies to trigger a re-render.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* Optionally include an array of dependencies to trigger a re-render.
* Include an array of dependencies to trigger a re-render.

Copy link
Contributor

Choose a reason for hiding this comment

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

One last nitpick 🤣

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just noticed that and fixed right before I saw this 😆

Covered with 0c1d8d9 — I went with: Re-render the calling component when the window is resized or dependencies update.

Copy link
Contributor Author

@mike-day mike-day Mar 15, 2023

Choose a reason for hiding this comment

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

Love those 1-liner blocks:

Screenshot 2023-03-14 at 9 10 04 PM

Screenshot 2023-03-14 at 9 10 43 PM

Copy link
Contributor

Choose a reason for hiding this comment

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

Haha, you beat me to it!

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 great 1-liner!

@mike-day mike-day merged commit 5f5efb7 into main Mar 15, 2023
@mike-day mike-day deleted the try/force-rerender-all-stale-previews branch March 15, 2023 14:36
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants