Description
This is a follow-up from #422 (comment)
Describe the bug:
The problem is visible at https://github.com/woocommerce/google-listings-and-ads/tree/2e5d58ac1f67f01ee33e076d03014c68ac38311d
What we do:
- We have a default state of
[]
-google-listings-and-ads/js/src/data/reducer.js
Lines 16 to 17 in 2e5d58a
EditFreeCampaign
fetches shipping rates from the server-side -EditFreeCampaign > SetupFreeListing > From
renders givenshippingRate
.
Expected behavior:
From
should eventually render data fetched from the server-side.
Actual behavior:
Sometimes, if racy flows align, the user gets the form with no shipping rates. Gets stuck with the initial data []
.
Steps to reproduce:
- Checkout https://github.com/woocommerce/google-listings-and-ads/tree/2e5d58ac1f67f01ee33e076d03014c68ac38311d
- Go to https://gla1.test/wp-admin/admin.php?page=wc-admin&path=%2Fgoogle%2Fedit-free-campaign&programId=123&pageStep=2
Additional details:
To me it looks like the problem is three fold:
Form
The first problem we have is that the <Form>
component uses initialValues
to create its own internal state, then ignores subsequent changes made to this prop. I believe it's a faulty implementation and something that should be addressed there.
From our (GLA) perspective fixing it there may take too long, as:
- this is an external component, with its own governance and release flow
- this is undocumented and untested behavior, therefore other plugins could rely on this as a feature
wp-data & isResolving
We should be able to solve that on our end by not rendering the Form
until the data is ready.
But we cannot.
With the way we obtain the data, we cannot distinguish whether the data was already loaded or not.
google-listings-and-ads/js/src/hooks/useShippingRates.js
Lines 13 to 21 in 2e5d58a
The
loading
flag indicates whether the request is taking place, no whether we asked for it.So from
EditFeeCampaign
or Form
perspective, the timeline would look like this:
- default state is
[]
- we call
const { data: savedShippingRates, loading } = useShippingRates();
.savedShippingRates
is[]
(default),loading
isfalse
- a moment later
savedShippingRates
is[]
(default),loading
istrue
- once data comes
savedShippingRates
is[...]
,loading
isfalse
(see https://github.com/woocommerce/google-listings-and-ads/tree/85612854603bd1d36f8d879d064af5d048109c11)
The problem is just by using those two variables savedShippingRates
and loading
we cannot judge whether it's the default state or the one fetched from the server-side. (empty array []
could be a valid saved state as well)
That means we may need to change the method we fetch the data, to expose information whether it was fetched or not.
Default
I also start to wonder whether []
is a good default/initial state. Before any data is loaded, do we really consider shipping.rates
and .times
to be an array ready for manipulation? For example, do we want to allow adding and removing items from it? For other entries like settings
we have null
not {}
. I think we may do the same for rates
and times
//cc @eason9487 @ecgan as you were supporting me in finding a solution for that.