Frontend application context

The application context contains the global state for use within the entire frontend application.

It's created using React's Context API. You can find more information in React's official documentation. It's similar (and React's answer) to Redux's Provider, which also wraps an application and gives any components access to a global state.

Currently, the FrontasticState consists of a single useCart object. However, this is likely to change as additional state objects are added as required, for example, useAccount.

These types are defined as below:

interface UseCart {
data?: Cart;
addItem: (variant: Variant, quantity: number) => Promise<void>;
updateCart: (payload: CartDetails) => Promise<void>;
setShippingMethod: (shippingMethodId: string) => Promise<void>;
removeItem: (lineItemId: string) => Promise<void>;
updateItem: (lineItemId: string, newQuantity: number) => Promise<void>;
shippingMethods: { data?: ShippingMethod[] };
orderCart: () => Promise<void>;
}
interface FrontasticState {
useCart: UseCart;
}

UseCart contains a mix of actions to mutate the cart, as well as data objects themselves. All GET actions (for example, cartItems and shippingMethods) use swr (a library of React hooks) to fetch data and update on mutation, and post actions use our fetcher and then the mutate function to update the state on successful updates and revalidate against stale data.

You can find more information in SWR's documentation. As swr uses React hooks, it's also important to note they follow React's rules of hooks.

How and where to use it

Most of the logic and exports are defined in packages/<project>/frontend/frontastic/lib/provider.tsx.

The logic for accessing the context is wrapped up nicely in exported functions that access the context and return the relevant object with data and actions, so they can be imported where needed and used accordingly.

An example component and usage can be seen below:

import { useCart } from 'frontastic';
import LineItemComponent from '...';
interface Props {
...
}
const MyComponent = ({ ... }: Props) => {
const { data, removeItem } = useCart();
const removeLineItem = (lineItemId: string) => removeItem(lineItemId);
return data?.lineItems.map((lineItem, i) => <LineItemComponent
key={i}
lineItem={lineItem}
removeLineItem={() => removeLineItem(lineItem.lineItemId)}
/>);
}