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

Fix Featured Product Search not working for large stores #5156

Merged
merged 2 commits into from
Dec 2, 2021

Conversation

alexflorisca
Copy link
Member

On the editor, after inserting a featured product block, the search does not return any results for large stores (with more than 100 products currently). This is due to the behaviour of the WithSearchedProducts higher order component. This generates a request to fetch products, both on a user searching, and every time the user changes a selection.

What's happening is this useEffect is ran on (almost) every render, because selected is an array that is checked by reference and it will have a different array instance each time the component is invoked, even if the value of the array hasn't changed.

The solution proposed here simply removes selected from the dependency array so that getProducts will only run once on the first render. From what I can see, there is no need to getProducts after each selection, and there is a separate call to getProducts in the onSearch callback. This looks to me like the intended behaviour but please point out if I'm missing something.

I've also explored memoizing the selected array with useMemo() but this still doesn't work, presumably because it's a different array each time.

Yet another solution would be to use JSON.stringify(selected) to check for the change in value of the selected array as described here. We could do this if this useEffect needs to run on every product selection.

Also eslint is throwing a warning about React Hook useEffect has a missing dependency: 'selected'. Either include it or remove the dependency array. But for this situation I think this is the right setting so I would disable the warning for this line but wanted to check first. Open to suggestions on this.

Fixes #4983

Screenshots

Before:
image

After:
image

Testing

Manual Testing

How to test the changes in this Pull Request:

  1. Have a large catalog, or edit here and here and set 100 to 5 say
  2. Insert Featured Product Block in the editor
  3. Enter a search term for a product not visible in the list
  4. Should see relevant search results based on search

Performance Impact

Changelog

Fixed Featured Product Block search not working for large stores

@alexflorisca alexflorisca added type: bug The issue/PR concerns a confirmed bug. focus: blocks Specific work involving or impacting how blocks behave. block: featured product Issues related to the Featured Product block. labels Nov 16, 2021
@alexflorisca alexflorisca self-assigned this Nov 16, 2021
@rubikuserbot rubikuserbot requested review from a team and ralucaStan and removed request for a team November 16, 2021 15:53
@alexflorisca alexflorisca requested a review from opr November 16, 2021 15:53
@github-actions
Copy link
Contributor

github-actions bot commented Nov 16, 2021

Size Change: +4.76 kB (0%)

Total Size: 1.12 MB

Filename Size Change
build/active-filters-frontend.js 8.24 kB +59 B (+1%)
build/active-filters.js 8 kB +5 B (0%)
build/all-products-frontend.js 23.5 kB +51 B (0%)
build/all-products.js 38.3 kB +22 B (0%)
build/atomic-block-components/add-to-cart--atomic-block-components/button--atomic-block-components/image---a7e2bb9b.js 3.2 kB +2 B (0%)
build/atomic-block-components/add-to-cart--atomic-block-components/button.js 1.81 kB +1 B (0%)
build/atomic-block-components/button.js 876 B +3 B (0%)
build/atomic-block-components/image.js 1.36 kB -3 B (0%)
build/atomic-block-components/price.js 2.11 kB +1 B (0%)
build/atomic-block-components/summary.js 911 B -1 B (0%)
build/atomic-block-components/title.js 1.47 kB -1 B (0%)
build/attribute-filter-frontend.js 18.2 kB +52 B (0%)
build/attribute-filter.js 12.1 kB +11 B (0%)
build/blocks-checkout.js 21.3 kB +6 B (0%)
build/cart-blocks/express-payment--checkout-blocks/express-payment--checkout-blocks/payment-frontend.js 4.74 kB +15 B (0%)
build/cart-blocks/line-items-frontend.js 5.87 kB -4 B (0%)
build/cart-frontend.js 52.6 kB +46 B (0%)
build/cart.js 50.7 kB +119 B (0%)
build/checkout-blocks/actions-frontend.js 1.48 kB +1 B (0%)
build/checkout-blocks/order-summary-frontend.js 12.9 kB +1 B (0%)
build/checkout-blocks/payment-frontend.js 4.47 kB +185 B (+4%)
build/checkout-frontend.js 54.9 kB +53 B (0%)
build/checkout.js 54 kB +242 B (0%)
build/featured-product.js 9.44 kB +12 B (0%)
build/handpicked-products.js 6.29 kB +21 B (0%)
build/legacy-template.js 2.05 kB -73 B (-3%)
build/mini-cart-component-frontend.js 44.8 kB +397 B (+1%)
build/mini-cart.js 6.24 kB +519 B (+9%) 🔍
build/price-filter-frontend.js 14.2 kB +56 B (0%)
build/price-filter.js 9.65 kB +1 B (0%)
build/price-format.js 1.4 kB +28 B (+2%)
build/product-best-sellers.js 6.62 kB +4 B (0%)
build/product-category.js 7.48 kB -8 B (0%)
build/product-new.js 6.77 kB +1 B (0%)
build/product-on-sale.js 7.12 kB +2 B (0%)
build/product-search.js 2.7 kB -2 B (0%)
build/product-top-rated.js 6.74 kB +1 B (0%)
build/products-by-attribute.js 7.71 kB -2 B (0%)
build/reviews-by-category.js 11.5 kB -2 B (0%)
build/reviews-by-product.js 13 kB +14 B (0%)
build/reviews-frontend.js 9.03 kB +59 B (+1%)
build/single-product-frontend.js 26.9 kB +57 B (0%)
build/single-product.js 10 kB +21 B (0%)
build/stock-filter-frontend.js 8.68 kB +55 B (+1%)
build/stock-filter.js 7.81 kB +3 B (0%)
build/wc-blocks-editor-style-rtl.css 15.8 kB +109 B (+1%)
build/wc-blocks-editor-style.css 15.8 kB +104 B (+1%)
build/wc-blocks-registry.js 3.71 kB +1 B (0%)
build/wc-blocks-style-rtl.css 21.1 kB +39 B (0%)
build/wc-blocks-style.css 21.1 kB +37 B (0%)
build/wc-blocks-vendors.js 255 kB +94 B (0%)
build/wc-blocks.js 3.49 kB -4 B (0%)
build/mini-cart-contents.js 2.35 kB +2.35 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size
build/all-reviews.js 9.56 kB
build/atomic-block-components/add-to-cart-frontend.js 8.34 kB
build/atomic-block-components/add-to-cart.js 7.85 kB
build/atomic-block-components/button-frontend.js 1.74 kB
build/atomic-block-components/category-list-frontend.js 466 B
build/atomic-block-components/category-list.js 469 B
build/atomic-block-components/image-frontend.js 1.71 kB
build/atomic-block-components/price-frontend.js 2.13 kB
build/atomic-block-components/rating-frontend.js 562 B
build/atomic-block-components/rating.js 566 B
build/atomic-block-components/sale-badge-frontend.js 861 B
build/atomic-block-components/sale-badge.js 868 B
build/atomic-block-components/sku-frontend.js 390 B
build/atomic-block-components/sku.js 393 B
build/atomic-block-components/stock-indicator-frontend.js 611 B
build/atomic-block-components/stock-indicator.js 610 B
build/atomic-block-components/summary-frontend.js 907 B
build/atomic-block-components/tag-list-frontend.js 468 B
build/atomic-block-components/tag-list.js 471 B
build/atomic-block-components/title-frontend.js 1.47 kB
build/cart-blocks/accepted-payment-methods-frontend.js 1.39 kB
build/cart-blocks/checkout-button-frontend.js 1.21 kB
build/cart-blocks/empty-cart-frontend.js 348 B
build/cart-blocks/express-payment-frontend.js 1.59 kB
build/cart-blocks/filled-cart-frontend.js 805 B
build/cart-blocks/items-frontend.js 302 B
build/cart-blocks/order-summary--checkout-blocks/billing-address--checkout-blocks/shipping-address-frontend.js 3.69 kB
build/cart-blocks/order-summary-frontend.js 7.4 kB
build/cart-blocks/totals-frontend.js 324 B
build/checkout-blocks/billing-address-frontend.js 2.64 kB
build/checkout-blocks/contact-information-frontend.js 3.62 kB
build/checkout-blocks/express-payment-frontend.js 1.93 kB
build/checkout-blocks/fields-frontend.js 348 B
build/checkout-blocks/order-note-frontend.js 1.25 kB
build/checkout-blocks/shipping-address-frontend.js 2.72 kB
build/checkout-blocks/shipping-methods-frontend.js 5.54 kB
build/checkout-blocks/terms-frontend.js 1.29 kB
build/checkout-blocks/totals-frontend.js 329 B
build/featured-category.js 7.74 kB
build/mini-cart-frontend.js 2.34 kB
build/product-categories.js 3.38 kB
build/product-tag.js 6.6 kB
build/vendors--atomic-block-components/add-to-cart--cart-blocks/order-summary--checkout-blocks/billing-ad--c5eb4dcd-frontend.js 16.1 kB
build/vendors--atomic-block-components/add-to-cart-frontend.js 4.77 kB
build/vendors--atomic-block-components/price--cart-blocks/line-items--cart-blocks/order-summary--checkout--8a3571de-frontend.js 5.71 kB
build/vendors--cart-blocks/line-items--checkout-blocks/order-summary-frontend.js 3.14 kB
build/vendors--cart-blocks/order-summary--checkout-blocks/billing-address--checkout-blocks/order-summary---eb4d2cec-frontend.js 5.03 kB
build/wc-blocks-data.js 11.3 kB
build/wc-blocks-google-analytics.js 1.98 kB
build/wc-blocks-middleware.js 1.19 kB
build/wc-blocks-shared-context.js 1.54 kB
build/wc-blocks-shared-hocs.js 1.92 kB
build/wc-blocks-vendors-style-rtl.css 1.37 kB
build/wc-blocks-vendors-style.css 1.37 kB
build/wc-payment-method-bacs.js 806 B
build/wc-payment-method-cheque.js 806 B
build/wc-payment-method-cod.js 898 B
build/wc-payment-method-paypal.js 839 B
build/wc-payment-method-stripe.js 12.2 kB
build/wc-settings.js 2.91 kB

compressed-size-action

@@ -48,7 +48,7 @@ const withSearchedProducts = (
setIsLoading( false );
} )
.catch( setErrorState );
}, [ selected ] );
}, [] );
Copy link
Member

Choose a reason for hiding this comment

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

This is an anti pattern that we fought a bit to get rid off and refactor away from, because it causes hard to debug bugs.
If you feel like selected is not going to change much here, I'd suggest you have it a ref then?

const selectedRef = useRef( selected );

selectedRef.current;

This should achieve the same goal, and would not cause rerenders.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for pointing that out @senadir, I'd be curious to know more about the types of bugs this causes! I've changed the implementation to use a ref as you suggested.

Copy link
Member

Choose a reason for hiding this comment

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

Hey! This causes out of sync bugs, things running when not needed, and generally hard to find bugs, examples:
#3314
#3285

@alexflorisca
Copy link
Member Author

alexflorisca commented Nov 23, 2021 via email

@alexflorisca alexflorisca requested a review from senadir November 23, 2021 17:26
Copy link
Contributor

@opr opr left a comment

Choose a reason for hiding this comment

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

Is it expected to get two (debounced) requests every time you type into the search box? I get the following two:

  • /wp-json/wc/store/products?per_page=5&catalog_visibility=any&search=beanie&orderby=title&order=asc&_locale=user
  • /wp-json/wc/store/products?catalog_visibility=any&include%5B0%5D=0&per_page=0&_locale=user

@alexflorisca
Copy link
Member Author

Is it expected to get two (debounced) requests every time you type into the search box? I get the following two:

  • /wp-json/wc/store/products?per_page=5&catalog_visibility=any&search=beanie&orderby=title&order=asc&_locale=user
  • /wp-json/wc/store/products?catalog_visibility=any&include%5B0%5D=0&per_page=0&_locale=user

It looks like the getProductsRequest method ads another request here - it makes another request to get the currently selected item, because searching again on a large store will change the list of results based on search and may remove the currently selected item from the dom. So it looks like it's meant to be there :)

@senadir
Copy link
Member

senadir commented Dec 1, 2021

I was under the impression that if the argument list is empty, it will actually avoid re-renders (only once) so it’s a good way to say “I only want this to run once”.

Yes, that's still the case, however, we want to avoid diverging from that eslint rule, not adding things to the deps rule to achieve that indicates a code smell and an issue to fix higher up, or with an alternate solution.

@alexflorisca alexflorisca requested a review from opr December 1, 2021 12:52
Copy link
Contributor

@opr opr left a comment

Choose a reason for hiding this comment

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

it looks like the getProductsRequest method ads another request here - it makes another request to get the currently selected item, because searching again on a large store will change the list of results based on search and may remove the currently selected item from the dom. So it looks like it's meant to be there :)

OK thanks! If this second request is necessary then I'm happy to approve. 🚢 👍🏼

@github-actions github-actions bot added this to the 6.5.0 milestone Dec 2, 2021
@alexflorisca alexflorisca merged commit 2c29a8d into trunk Dec 2, 2021
@alexflorisca alexflorisca deleted the fix/product-search branch December 2, 2021 18:51
jonny-bull pushed a commit to jonny-bull/woocommerce-gutenberg-products-block that referenced this pull request Dec 14, 2021
…#5156)

* Remove the dependency from the getProducts useEffect

* using ref instead of empty dependency array for useEffect
jonny-bull pushed a commit to jonny-bull/woocommerce-gutenberg-products-block that referenced this pull request Dec 16, 2021
…#5156)

* Remove the dependency from the getProducts useEffect

* using ref instead of empty dependency array for useEffect
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
block: featured product Issues related to the Featured Product block. focus: blocks Specific work involving or impacting how blocks behave. type: bug The issue/PR concerns a confirmed bug.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Featured Product Block Search is Broken
3 participants