Skip to content

Commit a85c281

Browse files
committed
feat(core): CHECKOUT-9513 Pass initial state through separate method to reduce work in single microtask
1 parent 6379d3a commit a85c281

14 files changed

+72
-55
lines changed

packages/core/src/billing/billing-address-reducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function dataReducer(
4343
return replace(data, action.payload && action.payload.billingAddress);
4444

4545
case CheckoutHydrateActionType.HydrateInitialState:
46-
return replace(data, action.payload?.checkout.billingAddress);
46+
return replace(data, action.payload?.checkout?.billingAddress);
4747

4848
default:
4949
return data;

packages/core/src/cart/cart-reducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ function dataReducer(
5555
return objectMerge(data, action.payload && action.payload.cart);
5656

5757
case CheckoutHydrateActionType.HydrateInitialState:
58-
return objectMerge(data, action.payload?.checkout.cart);
58+
return objectMerge(data, action.payload?.checkout?.cart);
5959

6060
default:
6161
return data;

packages/core/src/checkout/checkout-action-creator.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createAction, createErrorAction, ThunkAction } from '@bigcommerce/data-store';
1+
import { Action, createAction, createErrorAction, ThunkAction } from '@bigcommerce/data-store';
22
import { concat, defer, merge, Observable, of } from 'rxjs';
33
import { catchError } from 'rxjs/operators';
44

@@ -10,6 +10,8 @@ import { FormFieldsActionCreator } from '../form';
1010

1111
import Checkout, { CheckoutRequestBody } from './checkout';
1212
import { CheckoutActionType, LoadCheckoutAction, UpdateCheckoutAction } from './checkout-actions';
13+
import { CheckoutHydrateActionType } from './checkout-hydrate-actions';
14+
import CheckoutInitialState from './checkout-initial-state';
1315
import CheckoutRequestSender from './checkout-request-sender';
1416
import InternalCheckoutSelectors from './internal-checkout-selectors';
1517

@@ -143,6 +145,13 @@ export default class CheckoutActionCreator {
143145
};
144146
}
145147

148+
hydrateInitialState(state: CheckoutInitialState): Action<CheckoutInitialState> {
149+
return {
150+
type: CheckoutHydrateActionType.HydrateInitialState,
151+
payload: state,
152+
};
153+
}
154+
146155
private _transformCustomerAddresses(body: Checkout): Checkout {
147156
return {
148157
...body,

packages/core/src/checkout/checkout-initial-state.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { FormFields } from '../form';
55
import Checkout from './checkout';
66

77
export default interface CheckoutInitialState {
8-
config: Config;
9-
formFields: FormFields;
10-
checkout: Checkout;
11-
extensions: Extension[];
8+
config?: Config;
9+
formFields?: FormFields;
10+
checkout?: Checkout;
11+
extensions?: Extension[];
1212
}

packages/core/src/checkout/checkout-reducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ import { SpamProtectionAction, SpamProtectionActionType } from '../spam-protecti
1616
import { StoreCreditAction, StoreCreditActionType } from '../store-credit';
1717

1818
import { CheckoutAction, CheckoutActionType } from './checkout-actions';
19+
import { CheckoutHydrateAction, CheckoutHydrateActionType } from './checkout-hydrate-actions';
1920
import CheckoutState, {
2021
CheckoutDataState,
2122
CheckoutErrorsState,
2223
CheckoutStatusesState,
2324
DEFAULT_STATE,
2425
} from './checkout-state';
25-
import { CheckoutHydrateAction, CheckoutHydrateActionType } from './checkout-hydrate-actions';
2626

2727
export default function checkoutReducer(
2828
state: CheckoutState = DEFAULT_STATE,

packages/core/src/checkout/checkout-service.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ import { StoreCreditActionCreator, StoreCreditRequestSender } from '../store-cre
108108
import { SubscriptionsActionCreator, SubscriptionsRequestSender } from '../subscription';
109109

110110
import CheckoutActionCreator from './checkout-action-creator';
111+
import CheckoutInitialState from './checkout-initial-state';
111112
import CheckoutRequestSender from './checkout-request-sender';
112113
import CheckoutSelectors from './checkout-selectors';
113114
import CheckoutService from './checkout-service';
@@ -1630,4 +1631,24 @@ describe('CheckoutService', () => {
16301631
);
16311632
});
16321633
});
1634+
1635+
describe('#hydrateInitialState', () => {
1636+
it('creates instance with initial data', async () => {
1637+
const initialState: CheckoutInitialState = {
1638+
config: getConfig(),
1639+
formFields: getFormFields(),
1640+
checkout: getCheckout(),
1641+
extensions: getExtensions(),
1642+
};
1643+
1644+
const state = await checkoutService.hydrateInitialState(initialState);
1645+
1646+
expect(state.data.getCheckout()).toEqual(initialState.checkout);
1647+
expect(state.data.getConfig()).toEqual(initialState.config?.storeConfig);
1648+
expect(state.data.getCustomerAccountFields()).toEqual(
1649+
initialState.formFields?.customerAccount,
1650+
);
1651+
expect(state.data.getExtensions()).toEqual(initialState.extensions);
1652+
});
1653+
});
16331654
});

packages/core/src/checkout/checkout-service.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import { Subscriptions, SubscriptionsActionCreator } from '../subscription';
6060

6161
import { CheckoutRequestBody } from './checkout';
6262
import CheckoutActionCreator from './checkout-action-creator';
63+
import CheckoutInitialState from './checkout-initial-state';
6364
import CheckoutParams from './checkout-params';
6465
import CheckoutSelectors from './checkout-selectors';
6566
import CheckoutStore from './checkout-store';
@@ -180,6 +181,29 @@ export default class CheckoutService {
180181
return this._storeProjection.subscribe(subscriber, ...filters);
181182
}
182183

184+
/**
185+
* Hydrates the checkout service with an initial state.
186+
*
187+
* The initial state can contain various checkout data such as cart items,
188+
* customer information, and other relevant state.
189+
*
190+
* ```js
191+
* const initialState = {
192+
* // ... initial checkout state data
193+
* };
194+
*
195+
* const state = await service.hydrateInitialState(initialState);
196+
*
197+
* console.log(state.data.getCheckout());
198+
* ```
199+
*
200+
* @param state - The initial state data to hydrate the checkout service with.
201+
* @returns A promise that resolves to the current state after hydration.
202+
*/
203+
hydrateInitialState(state: CheckoutInitialState): Promise<CheckoutSelectors> {
204+
return this._dispatch(this._checkoutActionCreator.hydrateInitialState(state));
205+
}
206+
183207
/**
184208
* Loads the current checkout.
185209
*

packages/core/src/checkout/create-checkout-service.spec.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
import { createRequestSender } from '@bigcommerce/request-sender';
22

33
import { getDefaultLogger, Logger } from '../common/log';
4-
import { getConfig } from '../config/configs.mock';
5-
import { getExtensions } from '../extension/extension.mock';
6-
import { getFormFields } from '../form/form.mock';
74

8-
import CheckoutInitialState from './checkout-initial-state';
95
import CheckoutService from './checkout-service';
10-
import { getCheckout } from './checkouts.mock';
116
import createCheckoutService from './create-checkout-service';
127

138
jest.mock('@bigcommerce/request-sender');
@@ -48,23 +43,4 @@ describe('createCheckoutService()', () => {
4843

4944
expect(logger.warn).toHaveBeenCalled();
5045
});
51-
52-
it('creates instance with initial data', () => {
53-
const initialState: CheckoutInitialState = {
54-
config: getConfig(),
55-
formFields: getFormFields(),
56-
checkout: getCheckout(),
57-
extensions: getExtensions(),
58-
};
59-
const checkoutService = createCheckoutService({ initialState });
60-
const state = checkoutService.getState();
61-
62-
expect(checkoutService).toBeInstanceOf(CheckoutService);
63-
expect(state.data.getCheckout()).toEqual(initialState.checkout);
64-
expect(state.data.getConfig()).toEqual(initialState.config.storeConfig);
65-
expect(state.data.getCustomerAccountFields()).toEqual(
66-
initialState.formFields.customerAccount,
67-
);
68-
expect(state.data.getExtensions()).toEqual(initialState.extensions);
69-
});
7046
});

packages/core/src/checkout/create-checkout-service.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ import { StoreCreditActionCreator, StoreCreditRequestSender } from '../store-cre
6161
import { SubscriptionsActionCreator, SubscriptionsRequestSender } from '../subscription';
6262

6363
import CheckoutActionCreator from './checkout-action-creator';
64-
import CheckoutInitialState from './checkout-initial-state';
6564
import CheckoutRequestSender from './checkout-request-sender';
6665
import CheckoutService from './checkout-service';
6766
import CheckoutValidator from './checkout-validator';
@@ -110,7 +109,7 @@ export default function createCheckoutService(options?: CheckoutServiceOptions):
110109
};
111110
const { locale = '', shouldWarnMutation = true } = options || {};
112111
const requestSender = createRequestSender({ host: options && options.host });
113-
const store = createCheckoutStore({ config }, options?.initialState, { shouldWarnMutation });
112+
const store = createCheckoutStore({ config }, { shouldWarnMutation });
114113
const paymentClient = createPaymentClient(store);
115114
const orderRequestSender = new OrderRequestSender(requestSender);
116115
const checkoutRequestSender = new CheckoutRequestSender(requestSender);
@@ -214,5 +213,4 @@ export interface CheckoutServiceOptions {
214213
host?: string;
215214
shouldWarnMutation?: boolean;
216215
externalSource?: string;
217-
initialState?: CheckoutInitialState;
218216
}

packages/core/src/checkout/create-checkout-store.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { createDataStore } from '@bigcommerce/data-store';
22

33
import { createRequestErrorFactory } from '../common/error';
44

5-
import { CheckoutHydrateActionType } from './checkout-hydrate-actions';
6-
import CheckoutInitialState from './checkout-initial-state';
75
import CheckoutStore, { CheckoutStoreOptions } from './checkout-store';
86
import CheckoutStoreState from './checkout-store-state';
97
import createActionTransformer from './create-action-transformer';
@@ -12,25 +10,16 @@ import { createInternalCheckoutSelectorsFactory } from './create-internal-checko
1210

1311
export default function createCheckoutStore(
1412
initialStoreState: Partial<CheckoutStoreState> = {},
15-
initialServerState?: CheckoutInitialState,
1613
options?: CheckoutStoreOptions,
1714
): CheckoutStore {
1815
const actionTransformer = createActionTransformer(createRequestErrorFactory());
1916
const createInternalCheckoutSelectors = createInternalCheckoutSelectorsFactory();
2017
const stateTransformer = (state: CheckoutStoreState) => createInternalCheckoutSelectors(state);
2118
const reducer = createCheckoutStoreReducer();
22-
const hydrateAction = {
23-
type: CheckoutHydrateActionType.HydrateInitialState,
24-
payload: initialServerState,
25-
};
2619

27-
return createDataStore(
28-
reducer,
29-
reducer(initialStoreState as CheckoutStoreState, hydrateAction),
30-
{
31-
actionTransformer,
32-
stateTransformer,
33-
...options,
34-
},
35-
);
20+
return createDataStore(reducer, initialStoreState, {
21+
actionTransformer,
22+
stateTransformer,
23+
...options,
24+
});
3625
}

0 commit comments

Comments
 (0)