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

Options: Add data store #4144

Merged
merged 2 commits into from
Jun 10, 2020
Merged

Options: Add data store #4144

merged 2 commits into from
Jun 10, 2020

Conversation

psealock
Copy link
Collaborator

@psealock psealock commented Apr 17, 2020

Adds an options data store to replace wc-api/options.

Testing Instructions

  1. Smoke test the OBW and Task List.
  2. Check for no differences in behaviour.
  3. The "Customize your store" task list and payment steps included the most significant refactors of logic.

@psealock psealock force-pushed the add/options-data-store branch 2 times, most recently from ce3d0a9 to 7ad2265 Compare April 27, 2020 23:43
@psealock psealock requested a review from a team April 27, 2020 23:50
@@ -409,13 +413,19 @@ class TaskDashboard extends Component {
}

export default compose(
window.wcSettings.preloadOptions
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you do this with an if statement? It seems a little complicated for what it does.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I originally had it like this:

withOptionsHydration( {
    ...( window.wcSettings.preloadOptions || {} ),
} )

It was nicer to read, but I'd rather not call the hydration function if the data isn't there because resolvers in the data store will cache the empty values, preventing future api requests from going through.

@becdetat
Copy link
Contributor

You've used 'recieved' instead of 'received'. Apart from that and the question about an if this looks good :-)

@psealock psealock force-pushed the add/options-data-store branch from 7ad2265 to aad2c8f Compare April 29, 2020 23:54
@psealock psealock force-pushed the add/options-data-store branch 2 times, most recently from c986d9f to b8c7c15 Compare April 30, 2020 22:12
Copy link
Contributor

@joshuatf joshuatf left a comment

Choose a reason for hiding this comment

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

Will give this a more thorough look and test on Monday, but overall looks really solid. 💯

Left a couple comments and possible update to how we check for requesting. Thanks for all your effort here, Paul! This is really awesome work.

*
* @param {Object} state - Reducer state
*/
export const isGetOptionsRequesting = ( state ) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can replace these additional selectors with those built in to wp data. Outlined an issue with more detail here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thats an excellent idea! The way this is setup is getOptions calls resolver getOptionsWithRequest if the option hasn't been preloaded, which leaves us with this:

const options = getOptions( args );
const isRequesting = ( 'getOptionsWithRequest', [ args ] ) );
// What we really want is this:
// const isRequesting = ( 'getOptions', [ args ] ) );

More on why its that way in p90Yrv-1uN#comment-3842.

One option is to introduce isOptionsResolving to map resolver names. This is less than ideal because I'd rather hide implementation details from the consumer.

export const isOptionsResolving = ( state, selectorName, args ) => {
	return select( STORE_NAME ).isResolving(
		selectorName === 'getOptions' ? 'getOptionsWithRequest' : selectorName,
		args
	);
};

Any other ideas?

Copy link
Contributor

Choose a reason for hiding this comment

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

Another option would be to get rid of getOptions all together and just have any request for data always go through getOption to simplify the code.

I think I like this idea the best. It's a simple and easy to understand API and fixes issues with caching or needing to call with the exact same arguments used to determine resolution.

I originally wrote getOptions with an array for the purpose of avoiding multiple trips to the server when multiple options were needed, but if we wanted to keep this from a performance perspective, maybe we could collect requests for options and then fetch at the end of the stack.

For example, assume option A is cached but B and C need to be fetched and optionsToRequest and fetches are available across calls.

// in component
const a = getOption( 'a' );
const b = getOption( 'b' );
const c = getOption( 'c' );

// in resolvers, store a persisted array of items that need to be requested
optionsToRequest.push( optionName );

// Use a timeout of 1ms to push to the end of the stack
setTimeout( () => {
  // optionsToRequest should now be ['b', 'c']
  // Avoid fetching multiple times for a group of options.
  fetchPromise = fetches[ optionsToRequest.join(',') ]
  if ( fetchStarted ) {
     yield fetchPromise;
     return;
  }

  // fetch options in array optionsToRequest
  fetches[ optionsToRequest.join(',') ]  = yield apiFetch( {
    path: url,
    method: 'GET',
    data: optionsToRequest
   } );
  
}, 1 );

Do you think something like that is feasible?

Copy link
Collaborator Author

@psealock psealock May 26, 2020

Choose a reason for hiding this comment

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

Nice one @joshuatf !

I like the request collection technique. The thing that deterred me from this solution was it complicating the hydration part because I'll need to loop through all of the options individually. I got a solution to that one though.

packages/data/src/options/action-types.js Outdated Show resolved Hide resolved
@joshuatf joshuatf added needs: author feedback The issue/PR needs a response from any of the parties involved in the issue. and removed [Status] Needs Review labels May 20, 2020
@timmyc
Copy link
Contributor

timmyc commented Jun 1, 2020

@psealock looks like this might need a rebase ( and possibly a tough one at that ) - is there more work that needs to be done here, and can we coordinate it in such a way so you don't get hit with another hefty merge conflict?

@psealock psealock added status: in progress and removed needs: author feedback The issue/PR needs a response from any of the parties involved in the issue. labels Jun 4, 2020
@psealock psealock force-pushed the add/options-data-store branch 3 times, most recently from bb50a0e to a884649 Compare June 4, 2020 23:10
@psealock
Copy link
Collaborator Author

psealock commented Jun 8, 2020

@timmyc or @joshuatf Can you give this a look?

Copy link
Contributor

@timmyc timmyc left a comment

Choose a reason for hiding this comment

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

@psealock thanks for the work here and keeping on moving us forward on to wp.data.

Onboarding Profiler worked great for me. I'm seeing one oddity on the Setup Checklist. After configuring manual payment types ( COD and BACS ) the Payment step still was not being marked as done in the task list. I setup PayPal, and still, the option is never marked as completed. I don't think I have hit this before, so wondering if it is due to the changes here. I did not test in master to verify:

image

@psealock psealock force-pushed the add/options-data-store branch from e62280e to 0a7ce3d Compare June 10, 2020 02:41
@psealock
Copy link
Collaborator Author

I'm seeing one oddity on the Setup Checklist.

Yup, thanks. Thats an error which I fixed in 0a7ce3d.

I also rebased against master.

Copy link
Contributor

@joshuatf joshuatf left a comment

Choose a reason for hiding this comment

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

Testing really well for me. Awesome work, Paul!

Added one nitpick around statuses, but pre-approving.

} );

yield setIsUpdating( false );
return { status: 'success', ...results };
Copy link
Contributor

Choose a reason for hiding this comment

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

One minor nitpick, but I think we could update these to success: true|false to make checking easier and not manually checking against a string each time.

Though I think moving to an error-only checking approach may be more lean long-term (including response changes I recently made in the REST APIs). See p90Yrv-1KL-p2#comment-3981 for discussion around this.

it( 'should handle SET_REQUESTING_ERROR', () => {
const state = reducer( defaultState, {
type: TYPES.SET_REQUESTING_ERROR,
error: 'My bad',
Copy link
Contributor

Choose a reason for hiding this comment

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

😆

@psealock psealock force-pushed the add/options-data-store branch from 0a7ce3d to db3eed0 Compare June 10, 2020 23:40
@psealock
Copy link
Collaborator Author

Thanks for the review @joshuatf. I fixed the status to success: true | false in db3eed0

@psealock psealock merged commit a9acc23 into master Jun 10, 2020
@psealock psealock deleted the add/options-data-store branch June 10, 2020 23:49
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.

5 participants