# Upgrade to v3

As of v3, it's now possible to consume `@salesforce/retail-react-app` updates by adding it as an npm dependency and enabling [template extensibility](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/template-extensibility.md) in your project.

This guide covers how to update a PWA Kit project from v2.7.x to v3.

:::note
After completing the steps in this upgrade guide, we recommend that you test your site to confirm that it works as expected.
:::

:::tip
Only existing customers can access some of the links on this page. Visit [Salesforce Commerce Cloud GitHub Repositories and Access](https://developer.salesforce.com/docs/commerce/b2c-commerce/guide/b2c-github-repo-access.md) for information about how to get access to the repositories.
:::

## What’s New in v3

We’ve added lots of new features to PWA Kit v3, including:

⚛️ **Required**:

- `getProps` breaking change
- Major library updates, including support for **React 18**, **Node 22**, **Chakra 2**, and more

🔨 **Optional: Template extensibility** — Greatly reduce your project's code footprint and reduce development toil, cost of ownership, and future upgrade headaches. For more details, see the [Template Extensibility](/docs/commerce/b2c-commerce/guide/template-extensibility.md) guide!

**🪝 Optional:** **@salesforce/commerce-sdk-react "hooks" integration** — Decouples API calls from a project's implementation, allows API calls to be upgraded as an npm library dependency, and brings along many of the great features (including state management, and others) via [TanStack Query](https://tanstack.com/query/latest). See the [the Commerce SDK React docs](https://salesforcecommercecloud.github.io/pwa-kit/index.html) to get started!

## What’s New in All v3.x Versions

To learn about the features in all PWA Kit v3.x versions, see [pwa-kit](https://github.com/SalesforceCommerceCloud/pwa-kit/releases?q=v3\&expanded=true) on GitHub. Also, check out the PWA Kit release notes in [Composable Storefront Release Notes](/docs/commerce/pwa-kit-managed-runtime/references/about-pwa-kit-managed-runtime/about.md).

## Required Changes for Upgrading From v2

### New SDK Packages

The PWA Kit SDKs have been moved to the `@salesforce` NPM organization. To upgrade to v3, install the new packages and replace all import statements for the following packages:

- `pwa-kit-react-sdk` -> `@salesforce/pwa-kit-react-sdk@^3`
- `pwa-kit-runtime` -> `@salesforce/pwa-kit-runtime@^3`
- `pwa-kit-dev` -> `@salesforce/pwa-kit-dev@^3`
- `pwa-kit-create-app` -> `@salesforce/pwa-kit-create-app@^3`
- `retail-react-app` -> `@salesforce/retail-react-app@^3`

### Breaking Change for `getProps`

As of v3.0.0, PWA Kit introduces a new data fetching strategy `withReactQuery`. This strategy uses the react-query library and allows you to write React hooks to fetch data isomorphically. Unlike with `getProps`, you no longer need to duplicate the data fetching logic for the client side and the server side. In this version, by default, `@salesforce/retail-react-app` uses [`@salesforce/commerce-sdk-react`](https://salesforcecommercecloud.github.io/pwa-kit/) which is powered by [`react-query`](https://tanstack.com/query/latest).

```javascript
// app/components/_app-config/index.jsx

import {withLegacyGetProps} from '@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-legacy-get-props'

const AppConfig = ({children}) => {
  return <div>My AppConfig</div>
}

export default withLegacyGetProps(AppConfig)
```

:::note
- You can use both `withReactQuery` and `withLegacyGetProps` at the same time.
- `getProps` and `shouldGetProps` were removed from the default template of pages of the Retail React App, but aren’t deprecated. Long-term support for these methods remains.
:::

### Package Dependencies Upgrades

Change dependencies in package.json as shown below. Remove `@chakra-ui/system` from `peerDependencies` and include it under `dependencies` or `devDependencies`.

```json
"@chakra-ui/icons": "^2.0.19",
"@chakra-ui/react": "^2.6.0",
"@chakra-ui/skip-nav": "^2.0.15",
"@chakra-ui/system": "^2.5.6",
"framer-motion": "^10.12.9",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.43.9"
```

Update engines in package.json to support Node 22 and npm 9.

```json
"engines": {`
    "node": "^18.0.0",`
    "npm": "^8.0.0 || ^9.0.0"`
}
```

Reinstall dependencies for your project with `npm i`.

## Optional: Use Template Extensibility

When migrating from v2.7.x to v3.x you can choose whether you want to use Template Extensibility. To benefit from it, you must import at least one file from `@salesforce/retail-react-app` (or another extendable template in the future).

From there, consider how many files you have modified in from the original project that you generated via `npx pwa-kit-create-app@2.x`. Some customers have large numbers (perhaps hundreds) of files, but even then, a significant number can be unmodified. Those unmodified files are a good candidate for importing from `@salesforce/retail-react-app`, but we recommend doing this process carefully and gradually. Many files in `@salesforce/retail-react-app` are similar but have been changed from their previous state in `v2.x` of the PWA Kit Retail React App. In particular, the `@salesforce/commerce-sdk-react` integration (migration details covered in more detail later) has caused a large number of files to change in terms of their imports as well as their file structure, removing the entire `commerce-api` directory from the app, as a starting point that is in itself a significant change.

:::note
When migrating a project to use template extensibility, please note that version 2.x of the PWA Kit SDKs and projects generated via `npx pwa-kit-create-app@2.x` do not have a dependency on `@salesforce/commerce-sdk-react` whereas the newer code `@salesforce/retail-react-app@^1.x` makes heavy use of this library, which touches and changes many files. To get a sense of the magnitude of the changes, you can compare `release-2.7.x` → `release-3.0.x` in this Github diff <https://github.com/SalesforceCommerceCloud/pwa-kit/compare/release-2.7.x...release-3.0.x?diff=unified#files_bucket> and search for `@salesforce/commerce-sdk-react` and take note of all the additions that add this import.
:::

:::warning
If your app attempts to share code with version `2.x` (which includes the `app/commerce-api` directory), you risk adding unnecessary code to your bundle where that code exists (in two very different forms) in both the `commerce-api` folder and the `@salesforce/commerce-sdk-react` npm module.
:::

## Optional: Consume the commerce-sdk-react Hooks Library

As of v3.0.0, PWA Kit uses a different fetch strategy `withReactQuery`. This strategy leverages the react-query library and enables queries in the SSR rendering pass. The `@salesforce/retail-react-app` uses [`@salesforce/commerce-sdk-react`](https://salesforcecommercecloud.github.io/pwa-kit/) which is powered by [`react-query`](https://tanstack.com/query/latest).

In order for hooks to work on the server side, you need to wrap your `AppConfig` component with the new higher-order component `withReactQuery`.

:::warning
As part of the migration to ReactQuery as the default fetch strategy, `@salesforce/retail-react-app@^1` a change is required to ensure legacy `getProps()` calls continue to work.
:::

```javascript
// app/components/_app-config/index.jsx

import {CommerceApiProvider} from '@salesforce/commerce-sdk-react'
import {withReactQuery} from '@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-react-query'

const AppConfig = ({children}) => {
  return (
    <CommerceApiProvider
      clientId="12345678-1234-1234-1234-123412341234"
      organizationId="f_ecom_aaaa_001"
      proxy="localhost:3000/mobify/proxy/api"
      redirectURI="localhost:3000/callback"
      siteId="RefArch"
      shortCode="12345678"
      locale="en-US"
      currency="USD"
    >
      {children}
    </CommerceApiProvider>
  )
}

export default withReactQuery(AppConfig)
```

## Troubleshooting and Optimization

When you complete the dependency upgrades described above you may encounter issues in your project related to the below libraries. In the sections below we propose solutions for resolving these issues. The particulars of your project will vary and proposed solutions should be treated as guidelines and not absolute rules.

### Upgrade `react-hook-form`

For the `react-hook-form` migration, read the react-hook-form official doc [here](https://legacy.react-hook-form.com/migrate-v6-to-v7/). In the PWA project, there are two places that require changes:

1. Move form `errors` object into one more layer of destructing for hooks in `app/components/forms/` as the `errors` object has been moved into the `formState` object.

```javascript
   // app/components/forms/useAddressFields.jsx

    //before
    export default function useAddressFields({form: {watch, control, errors}, prefix = ''}) {

    //after
    export default function useAddressFields({
        form: {
            watch,
            control,
            formState: {errors}
        },
        prefix = ''
    })
```

2. Move the render props in `Controller`into the `field` prop. `Render`'s callback signature returns an object that contains `field` and `fieldState`.

```javascript
// app/components/field/index.jsx

    // before
    <Controller
        name={name}
        control={control}
        rules={rules}
        defaultValue={defaultValue}
        render={({onChange, value, ref}) => {
          // other code
        }}
    />

    // after
    <Controller
        name={name}
        control={control}
        rules={rules}
        defaultValue={defaultValue}
        render={({field: {onChange, value, ref}}) => {
          // other code
        }}
    />
```

### React 18 Hydration Error

As of React 18, hydration warnings are surfaced as errors instead of warnings as they had been in React 17. Some code updates were required to suppress these potential errors that prevent the application from building when there are hydration errors. It is essential to fix these errors to ensure the app can render isomorphically. This error occurs because there is a mismatch between server or client. If a component or a page happens to render conditionally, you must make sure that the hydration is finished before rendering any client-specific code.

In your project, create a utility function to determine if the hydration has finished. you can use a built-in variable provided by `window.__HYDRATING__` in `pwa-kit-react-sdk`.

```javascript
/**
 * This utility function determines if the app has finished hydration
 * @return {boolean}
 */
export const isHydrated = () => typeof window !== 'undefined' && !window.HYDRATING
```

### Chakra 2

:::important
If your project uses components and APIs from the `@chakra-ui/react` library that are different than the Retail React App template, review the official [Chakra migration docs](https://www.chakra-ui.com/docs/get-started/migration).
:::

To support Chakra 2, there are a few files that require updates for projects based on the Retail React App template:

Remove `allowToggle` in the `Accordion` component because `allowMultiple` and `allowToggle` can't be used at the same time in Chakra 2.

In the `Footer` component, importing `StylesProvider` directly from `@chakra-ui/react` is deprecated. You must create it via `createStylesContext('Footer')` instead.

```javascript
import {createStylesContext} from '@chakra-ui/react'

const [StylesProvider, useStyles] = createStylesContext('Footer')
```

### @testing-library/react

Set up `userEvent` before calling any action, and await the action in unit tests that uses `userEvent`because in React testing library v14.0.0, all the user actions are async, and it requires calling `setup`before performing user actions.

For example:

```javascript
const user = userEvent.setup()`
// Import `render`and`screen` from the framework library of your choice.
// See https://testing-library.com/docs/dom-testing-library/install#wrappers
render(<MyComponent />)

await user.click(screen.getByRole('button', {name: /click me!/i}))
```

For more details, see the official docs for [userEvent](https://testing-library.com/docs/user-event/intro) from testing-library.

Alternatively, to avoid repetitively calling setup()`in many unit tests, you can set up your`userEvent `in`app/utils/test-util.js`right before rendering the test component and return it along with render results so that the test can perform the user actions without having to call` setup()\`.

```javascript
export const renderWithProvider = (children, options) => {
   // some code here
   const user = userEvent.setup()
   const res = render(children, {
        wrapper: () => (
            <TestProvidersWithDataAPI {...options?.wrapperProps} locals={locals}>
                {children}
            </TestProvidersWithDataAPI>
        ),
        ...options
    })
    return {user, ...res}
}

//usage
test('some test', async () => {
   const {user} = renderWithProviders(<MyComponent />
   const button = screen.getByText(/button/)
   await user.click(button)
}
```

### Jest-setup

In jest-setup, there is a mock dependency that can throw an error about `TextDecoder` being undefined in `jest-setup.js.` Add the following to `jest-setup.js`:

```javascript
global.TextDecoder = require('util').TextDecoder
```

## Other Improvements

When migrating from version 2.x of the PWA Kit SDKs or projects generated via `npx pwa-kit-create-app@2.x`, the `@salesforce/commerce-sdk-react` code has been significantly refactored to remove the `app/commerce-api/` directory. Instead of those files handling API request and acting as an SDK, `@salesforce/commerce-sdk-react` supersedes that functionality. The v3 release of the SDKs correlates with the first release of `@salesforce/retail-react-app@^1.x` because the SDKs use this library a lot.

The implementation of `@salesforce/commerce-sdk-react` changes many files in the Retail React App. To get a sense of the size of the changes, compare `release-2.7.x` to `release-3.0.x` in this [GitHub diff](https://github.com/SalesforceCommerceCloud/pwa-kit/compare/release-2.7.x...release-3.0.x?diff=unified#files_bucket) and search for `@salesforce/commerce-sdk-react`. In the diff, take note of all the additions that include this import.
