# State Management

Some storefront applications demand a way to manage global state. There are many state-management libraries out there that help you do just that, such as [Redux](https://redux.js.org/) and [MobX](https://mobx.js.org/README.html). Salesforce does not endorse one particular state-management library over any other—and you can build a PWA Kit app without using one at all.

You can always provide state information to your components via props, but if you want to use React’s more advanced features for managing state, this guide covers other approaches too.

## Using Props

The simplest technique for sharing state among components is to provide that state information via props to a component. That component must be a parent to all the components that need to access the state data. The React docs describe this technique in detail and call it [lifting state up](https://reactjs.org/docs/lifting-state-up.html).

## Using the React Context API

React’s [Context API](https://reactjs.org/docs/context.html) simplifies the process of making data available to a large number of components, without having to manually pass that data through props at each level of your app’s component tree.

### React Context Example

Here’s an example of how you might use the React Context API with a component that acts as a wrapper around all of your components to provide them with shared state data.

Start by creating a component called `GlobalState` that has two context objects:

1. `GlobalStateContext`: where you can store global state data.
2. `GlobalDispatchContext`: your `dispatch` function, which returns an updated snapshot of global state through a reducer function.

Each context object comes with a `<Provider>` component that allows consuming components to subscribe to context changes. Here, the context objects are initialized with the props `initialState` and `dispatch`. You get these props when you connect your state with a `reducer`, using the `useReducer` Hook. For more information on React Hooks, including how to use them with the Context API, see the official [React Hooks reference documentation](https://reactjs.org/docs/hooks-reference.html).

Here’s how you would define and initialize a component that uses the Context API for storing global state in your storefront app:

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

import {createContext, useContext} from 'react'

export const GlobalContext = createContext()
export const useGlobalState = () => useContext(GlobalContext)

const AppConfig = (props) => {
    const [globalState, setGlobalState] = useState({
        customer: {name: 'Samantha', registered: true},
    })

    return (
        <GlobalContext.Provider value={(globalState, setGlobalState)}>
            {props.children}
        </GlobalContext.Provider>
    )
}

// app/pages/page/index.jsx

import React, {useContext} from 'react'
import {useGlobalState} from 'components/_app-config'

export const Page = () => {
    const {customer, setGlobalState} = useGlobalState()

    // Use setGlobalState to change the global state.

    return <div>{customer.name}</div>
}
```

The `AppConfig` special component located in `app/components/_app-config/index.jsx` is where you can initialize your state management system. Here, `props.children` contains all the components of your app, so that's where you want to add your `GlobalState` component.

To get the props object you need to initialize it first. Use the React Hook `useReducer` to create a connected state to your reducer. The `useReducer` function takes in an `initialState` object and the `reducer` imported from the GlobalState component. Next, pass in the connected state and a `dispatch` function to modify that state.

For example:

```javascript
// <PROJECT_DIR>/app/components/_app-config/index.jsx

// Replace your existing React imports
import React, { useState }, { useReducer }, from "react"

// Import GlobalState component defined in previous example
import GlobalState, { reducer } from "../global-state"

const initialState = {
  cart: null
}

// Combine this with your existing AppConfig component code
function AppConfig(props) {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <GlobalState initialState={state} dispatch={dispatch}>
      {props.children}
    </GlobalState>
  )
}
```

Now you can give any component access to your global context data, including the ability to update it. Import `GlobalStateContext` and `GlobalDispatchContext` from your `GlobalState` component and provide those context objects to the `useContext()` method.

For example:

```javascript
import React, {useContext} from 'react'
import {GlobalStateContext, GlobalDispatchContext, SET_CART_ITEMS} from 'app/components/global-state'

function ExamplePage() {
    const globalState = useContext(GlobalStateContext)
    const dispatch = useContext(GlobalDispatchContext)

    // Use this where you want to update the cart data in your global state
    dispatch({type: SET_CART_ITEMS, payload: cartItems})

    return ( /* render something */ )
}
```

## Using a State-Management Library

You can customize your application to use a state management library by overriding the default `AppConfig` special component located in `app/components/_app-config/index.jsx`.

### Redux Example

Here's how to set up Redux for your PWA by inside `AppConfig`. The component has four methods that you need to use:

1. The `restore` method is where you create your Redux store with a reducer, initial state, and any middleware.
2. The `freeze` method allows you to freeze your state management backend for embedding into the page HTML.
3. The `extraGetPropsArgs` method is where you can return any extra arguments that you’d like to inject into `getProps` methods across the entire app. In this case, we can return the Redux store as an extra argument.
4. The `render` method allows you to set up context providers for a state management library. For example, you can use it to wrap the app in a Redux provider.

Here is a brief example showing how to use the methods of `AppConfig` to set up Redux for your storefront app. In addition to the steps we show here, a complete solution requires you to create your store with a reducer, initial state, and any required middleware.

```javascript
// <PROJECT_DIR>/app/components/_app-config/index.jsx

// Combine these imports with your existing imports to include Redux
imports import React, { useState }, { useReducer }, from "react"
import PropTypes from "prop-types"
import { createStore } from "redux"
import { Provider } from "react-redux"

/**
 * Combine this code with your existing AppConfig code to use Redux by injecting store object and dispatch function into all getProps() functions.
 */

class AppConfig extends React.Component {
  static restore(locals, frozen = {}) {
    // create your store with a reducer, initial state, and any middleware.
    const initialState = isServerSide ? {} : frozen
    locals.store = createStore(reducer, initialState, middlewares)
  }
  static freeze(locals) {
    return locals.store.getState()
  }
  static extraGetPropsArgs(locals) {
    return {
      store: locals.store,
      dispatch: locals.store.dispatch
    }
  }

  /**
   * The render function will wrap the app in a Redux provider.
   */
  render() {
    const { children, locals } = this.props
    return <Provider store={locals.store}>{children}</Provider>
  }
}

AppConfig.propTypes = {
  children: PropTypes.node,
  locals: PropTypes.object
}

export default AppConfig
```
