Skip to content

Commit

Permalink
feat: useCart as shared component to increase performance
Browse files Browse the repository at this point in the history
  • Loading branch information
patzick committed Jan 17, 2023
1 parent dc6a551 commit c300b89
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 7 deletions.
7 changes: 7 additions & 0 deletions .changeset/hip-nails-sip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"vue-demo-store": minor
"@shopware-pwa/nuxt3-module": minor
"@shopware-pwa/composables-next": minor
---

Changed `useCart` in now a shared composable, so there is only one instance.
5 changes: 5 additions & 0 deletions .changeset/little-wasps-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"docs": patch
---

Added information about shared composables
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ out/
build
dist

# vitepress
**/.vitepress/cache

# misc
.DS_Store
*.pem
Expand Down
1 change: 1 addition & 0 deletions apps/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const sidebar = [
{ text: "Shopping Experiences", link: "/framework/shopping-experiences" },
{ text: "Styling", link: "/framework/styling" },
{ text: "Context Composables", link: "/framework/context-composables" },
{ text: "Shared Composables", link: "/framework/shared-composables" },
],
},
{
Expand Down
40 changes: 40 additions & 0 deletions apps/docs/src/framework/shared-composables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Shared composables

Using composable in a component can be imagined as copying all the code from that into that component, without the actual need to do so. This way we can reuse logic in a clean way. We need to remember, that every computed property/state is then replicated, so if we have multiple components using specific composable - we duplicate that in memory.

Sometimes we want only one instance of a specific composable to be shared between all components. This is where shared composables come in. They are just regular composables, but there is always one instance in the system.

Example:
`useCart` is composable which contains cart information, like items inside, count or totalPrice details. We want to use it in multiple components, but we don't want to duplicate the data in memory. This is a perfect use case for shared composable.

## How do I know which one is shared and what should I do with that?

We're adding information that the composable is shared into the description with a link to this documentation page.
There is no need to do anything with this information. The only difference is in [overwriting](#overwrite-extend-shared-composable)

## Overwrite/extend shared composable

Typically you extend shared composable by using the same core composable. In the case of shared composables you need to take `useXXFunction` to extend it.

Example:

```ts
import { useCartFunction } from "@shopware-pwa/composables-next";
import { createSharedComposable } from "@vueuse/core";

function myUseCart() {
const coreCartFunctions = useCartFunction();

// extend the core functions
const myCustomFunction = () => {
// do something
};

return {
...coreCartFunctions,
myCustomFunction,
};
}

export const useCart = createSharedComposable(myUseCart); // or skip `createSharedComposable` if you don't want it to be a shared composable anymore
```
15 changes: 10 additions & 5 deletions packages/composables/src/useCart.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ref, Ref, computed, ComputedRef, provide, inject } from "vue";
import { computed, ComputedRef } from "vue";
import {
getCart,
addProductToCart,
Expand All @@ -9,6 +9,8 @@ import {
} from "@shopware-pwa/api-client";
import { Cart, EntityError, Product, LineItem } from "@shopware-pwa/types";
import { useShopwareContext } from "./useShopwareContext";
import { _useContext } from "./internal/_useContext";
import { createSharedComposable } from "@vueuse/core";

export type UseCartReturn = {
/**
Expand Down Expand Up @@ -74,13 +76,14 @@ export type UseCartReturn = {
};

/**
* Composable for cart management
* Cart management logic.
*
* Used as [Shared](https://shopware-frontends-docs.vercel.app/framework/shared-composables.html) Composable `useCart`
*/
export function useCart(): UseCartReturn {
export function useCartFunction(): UseCartReturn {
const { apiInstance } = useShopwareContext();

const _storeCart: Ref<Cart | undefined> = inject("swCart", ref());
provide("swCart", _storeCart);
const _storeCart = _useContext<Cart | undefined>("swCart");

async function refreshCart(): Promise<Cart> {
const result = await getCart(apiInstance);
Expand Down Expand Up @@ -234,3 +237,5 @@ export function useCart(): UseCartReturn {
isEmpty,
};
}

export const useCart = createSharedComposable(useCartFunction);
14 changes: 12 additions & 2 deletions templates/vue-demo-store/pages/checkout/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const {
activeBillingAddress,
setActiveBillingAddress,
} = useSessionContext();
const { cartItems, subtotal, totalPrice, shippingTotal } = useCart();
const { cart, cartItems, subtotal, totalPrice, shippingTotal } = useCart();
const { customerAddresses, loadCustomerAddresses } = useAddress();
const modal = inject<SharedModal>("modal") as SharedModal;
const isLoading = reactive<{ [key: string]: boolean }>({});
Expand Down Expand Up @@ -83,6 +83,10 @@ const selectedBillingAddress = computed({
},
});
const isCartLoading = computed(() => {
return !cart.value;
});
const isCheckoutAvailable = computed(() => {
return cartItems.value.length > 0;
});
Expand Down Expand Up @@ -187,7 +191,13 @@ const invokeSubmit = async () => {

<template>
<div class="m-10">
<div v-if="isCheckoutAvailable" class="checkout-inner">
<div
v-if="isCheckoutAvailable || isCartLoading"
class="checkout-inner"
:class="{
'opacity-20': isCartLoading,
}"
>
<div class="md:grid md:grid-cols-2 md:gap-6">
<div class="md:col-span-1">
<div class="grid gap-4 shadow px-4 py-5 bg-white sm:p-6 mb-8">
Expand Down

0 comments on commit c300b89

Please sign in to comment.