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

Fix React hook dependency warnings in filter an All Products blocks #3285

Merged

Conversation

Aljullu
Copy link
Contributor

@Aljullu Aljullu commented Oct 14, 2020

Part of #3204.

This PR handles the React hook dependency warnings produced by ESLint in the filter and All Products blocks. Some fixes were trivial while some others needed bigger refactors. Adding new dependencies to effects/memos/callbacks might have caused them to do unnecessary recalculations, when that was evident, I tried to prevent it either wrapping some dependencies with useShallowEqual() or refactoring it completely. However, I might have missed some and for sure there are many more optimizations to do.

How to test the changes in this Pull Request:

The scope of changes in this PR is limited to the filter and All Products blocks, so those are the ones that need to be tested.

  1. Create a page with the Filter products by price, Filter products by attribute, Active filters and All Products blocks.
  2. Verify you can switch pages in the product list.
  3. Verify you can change the sorting order and it sets the page back to 1.
  4. Verify that when you activate a filter, the pagination goes back to 1.
  5. Try setting several filters at the same time, removing them, clearing them all at once, etc.
  6. Summarizing, try to break the blocks. 🙂
    In the process I found a couple of bugs (Price slider goes back to 0 after moving the min handle #3282 and Price slider max constraint doesn't match price filter input value woocommerce#42675), but I could reproduce them in trunk too, so I filled issues in GH.
  7. Repeat the process above but first edit the filter blocks so they have the 'Filter button' visible.
    imatge
  8. Extra testing modifying other attributes of the blocks would be great.

@Aljullu Aljullu added status: needs review type: refactor The issue/PR is related to refactoring. skip-changelog PRs that you don't want to appear in the changelog. labels Oct 14, 2020
@Aljullu Aljullu added this to the 3.7.0 milestone Oct 14, 2020
@Aljullu Aljullu requested a review from a team as a code owner October 14, 2020 15:30
@Aljullu Aljullu self-assigned this Oct 14, 2020
@Aljullu Aljullu requested review from senadir and removed request for a team October 14, 2020 15:30
@github-actions
Copy link
Contributor

github-actions bot commented Oct 14, 2020

Size Change: +577 B (0%)

Total Size: 1.12 MB

Filename Size Change
build/active-filters-frontend.js 8.9 kB +87 B (0%)
build/active-filters.js 8.94 kB +89 B (0%)
build/all-products-frontend.js 31.3 kB +8 B (0%)
build/all-products.js 36.1 kB +52 B (0%)
build/atomic-block-components/add-to-cart-frontend.js 8.94 kB -3 B (0%)
build/atomic-block-components/add-to-cart~atomic-block-components/button.js 3.19 kB +5 B (0%)
build/atomic-block-components/button.js 840 B +1 B
build/atomic-block-components/image-frontend.js 1.7 kB -1 B
build/atomic-block-components/image.js 1.15 kB -2 B (0%)
build/atomic-block-components/price-frontend.js 2.29 kB +1 B
build/atomic-block-components/price.js 2.32 kB -3 B (0%)
build/atomic-block-components/rating.js 526 B -1 B
build/atomic-block-components/sale-badge-frontend.js 857 B -2 B (0%)
build/atomic-block-components/title.js 1.06 kB +1 B
build/attribute-filter-frontend.js 18.3 kB +95 B (0%)
build/attribute-filter.js 12.5 kB +102 B (0%)
build/blocks.js 3.54 kB -2 B (0%)
build/cart-frontend.js 70 kB -11 B (0%)
build/cart.js 38.7 kB -8 B (0%)
build/checkout-frontend.js 85.9 kB -12 B (0%)
build/checkout.js 42 kB -16 B (0%)
build/handpicked-products.js 7.37 kB +2 B (0%)
build/price-filter-frontend.js 14.9 kB +124 B (0%)
build/price-filter.js 10.4 kB +107 B (1%)
build/product-best-sellers.js 7.45 kB -3 B (0%)
build/product-category.js 8.38 kB -3 B (0%)
build/product-new.js 7.61 kB -1 B
build/product-on-sale.js 8 kB -2 B (0%)
build/product-tag.js 6.53 kB +1 B
build/product-top-rated.js 7.58 kB -2 B (0%)
build/products-by-attribute.js 8.33 kB +2 B (0%)
build/reviews-by-product.js 13.4 kB -1 B
build/reviews-frontend.js 9.38 kB -16 B (0%)
build/single-product-frontend.js 33.8 kB -2 B (0%)
build/single-product.js 10.1 kB -3 B (0%)
build/vendors.js 417 kB -6 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/all-reviews.js 9.78 kB 0 B
build/atomic-block-components/add-to-cart.js 7.52 kB 0 B
build/atomic-block-components/add-to-cart~atomic-block-components/image~atomic-block-components/title.js 335 B 0 B
build/atomic-block-components/button-frontend.js 2.02 kB 0 B
build/atomic-block-components/category-list-frontend.js 469 B 0 B
build/atomic-block-components/category-list.js 478 B 0 B
build/atomic-block-components/rating-frontend.js 524 B 0 B
build/atomic-block-components/sale-badge.js 863 B 0 B
build/atomic-block-components/sku-frontend.js 386 B 0 B
build/atomic-block-components/sku.js 395 B 0 B
build/atomic-block-components/stock-indicator-frontend.js 568 B 0 B
build/atomic-block-components/stock-indicator.js 573 B 0 B
build/atomic-block-components/summary-frontend.js 917 B 0 B
build/atomic-block-components/summary.js 927 B 0 B
build/atomic-block-components/tag-list-frontend.js 467 B 0 B
build/atomic-block-components/tag-list.js 474 B 0 B
build/atomic-block-components/title-frontend.js 1.23 kB 0 B
build/editor-rtl.css 13.8 kB 0 B
build/editor.css 13.9 kB 0 B
build/featured-category.js 7.73 kB 0 B
build/featured-product.js 9.97 kB 0 B
build/product-categories.js 3.23 kB 0 B
build/product-search.js 3.56 kB 0 B
build/reviews-by-category.js 11.8 kB 0 B
build/style-rtl.css 17.9 kB 0 B
build/style.css 17.9 kB 0 B
build/vendors-style-rtl.css 1.03 kB 0 B
build/vendors-style.css 1.03 kB 0 B
build/vendors~atomic-block-components/price-frontend.js 5.65 kB 0 B
build/wc-blocks-data.js 7.1 kB 0 B
build/wc-blocks-middleware.js 931 B 0 B
build/wc-blocks-registry.js 2.32 kB 0 B
build/wc-payment-method-bacs.js 790 B 0 B
build/wc-payment-method-cheque.js 787 B 0 B
build/wc-payment-method-cod.js 879 B 0 B
build/wc-payment-method-paypal.js 831 B 0 B
build/wc-payment-method-stripe.js 12 kB 0 B
build/wc-settings.js 2.35 kB 0 B
build/wc-shared-context.js 1.53 kB 0 B
build/wc-shared-hocs.js 1.66 kB 0 B

compressed-size-action

@senadir
Copy link
Member

senadir commented Oct 19, 2020

Note that I'm aware of this PR and will get to it in the next couple of days unless it's blocking any other work or there's a risk it will get outdated quickly, in which case I can review it today?

@Aljullu
Copy link
Contributor Author

Aljullu commented Oct 19, 2020

Sounds good @senadir. I don't think there is any hurry as long as it's dealt with before the end of cooldown. 🙂

@Aljullu Aljullu force-pushed the refactor/fix-hook-dependency-warnings-filters-all-products branch from 08e3a96 to 0d4fd7a Compare October 22, 2020 11:11
Copy link
Member

@senadir senadir left a comment

Choose a reason for hiding this comment

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

I'm actually a bit scared of merging this 😅
It's a lot of changes that are not obvious to me, I can see possible hidden regressions in the future.
I followed the testing steps and nothing broke, so we're comfortable with that.
I can't think of any other testing scenario.

So, I'm going to approve this and would be happy to merge it.
However, if you have any free time now or later, I would really appreciate some comments here and there to justify the changes, it would be helpful for future developers if we track a bug down to this PR.

Usually, I would suggest doing that in a follow-up issue, but the more we delay this, the greater chances that you forget why you did those changes.

Copy link
Contributor Author

@Aljullu Aljullu left a comment

Choose a reason for hiding this comment

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

Thanks for the review @senadir. 💯 that it's very tricky to understand these changes, in fact it was a really complex PR to write. Also, they are blocks that we didn't touch for some time, so it required some 'context switching'.

I added inline comments to all changes included in this PR, I hope they will make it easier to understand the rationale behind the changes.

@@ -142,6 +142,7 @@ const CheckboxList = ( {
);
}, [
options,
onChange,
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 one was easy: missing dependency in a useMemo. onChange is not expected to change, but in order to fix the linting warning, it was needed.

@@ -186,7 +185,14 @@ const PriceSlider = ( {
parseInt( values[ 1 ], 10 ),
] );
},
[ minPrice, maxPrice, minConstraint, maxConstraint, stepValue ]
[
onChange,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similar as before, but in this case it's a useCallback().

maxPriceInput,
currency,
]
[ onChange, stepValue, minPriceInput, maxPriceInput ]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

onChange was a missing dependency, while minConstraint, maxConstraint and currency were listed as a dependency, but they are not used inside the callback.

@@ -96,6 +96,11 @@ const announceLoadingCompletion = ( totalProducts ) => {
}
};

const areQueryTotalsDifferent = (
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 extracted that function outside of the functional component so it's not re-created on every render. This prevents usePrevious() repeating the validation unnecessarily on every render if the value didn't change. See the changes in use-previous.js here:

https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3285/files#diff-0fa9d6144ce10110cc712ea2ff1988cb3d7e9eba087ca2ee2a5deb8d709dbe7eL23

Number.isFinite( val )
const previousConstraint = usePrevious(
currentConstraint,
Number.isFinite
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Avoids creating a new function on every render, which would cause usePrevious() running the validation function unnecessarily.

@@ -258,45 +258,42 @@ const Edit = ( { attributes, setAttributes, debouncedSpeak } ) => {
</Placeholder>
);

const onDone = useCallback( () => {
const onDone = () => {
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 don't think it made much sense wrapping this function in a useCallback() because it's not used inside any other hook.

if ( ! selected || ! selected.length ) {
return;
}
const onChange = ( selected ) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as before. 🙂

@@ -26,10 +27,12 @@ import usePriceConstraints from './use-price-constraints.js';
*/
const PriceFilterBlock = ( { attributes, isEditor = false } ) => {
const [ minPriceQuery, setMinPriceQuery ] = useQueryStateByKey(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

useQueryStateByKey() sets the default value to an empty object, I added the null parameter so the default value is null, this avoids unnecessary re-calculations when using minPriceQuery and maxPriceQuery in hook dependencies.

@@ -73,29 +81,61 @@ const PriceFilterBlock = ( { attributes, isEditor = false } ) => {
setMaxPrice( prices[ 1 ] );
}
},
[ minConstraint, maxConstraint, minPrice, maxPrice ]
[ minPrice, maxPrice, setMinPrice, setMaxPrice ]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Replacing wrong deps in this callback, this change should be safe.

previousMaxConstraint,
previousMinPriceQuery,
previousMaxPriceQuery,
] );
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 is probably the most complex change in this PR, this effect was relying on missing deps to be run only when the min/max query price or the min/max constraint changed. However, in order to fix the linting warnings we needed to add several missing dependencies. That mean the effect run more often than before, that's why I needed to add extra checks to ensure the query price or the constraints had changed.

@Aljullu Aljullu merged commit 7b18999 into trunk Oct 27, 2020
@Aljullu Aljullu deleted the refactor/fix-hook-dependency-warnings-filters-all-products branch October 27, 2020 15:39
@senadir
Copy link
Member

senadir commented Oct 27, 2020

Excellent explanation @Aljullu, Thank you for taking the time to write it.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
skip-changelog PRs that you don't want to appear in the changelog. type: refactor The issue/PR is related to refactoring.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants