Gestione dello stato

Alcune applicazioni storefront richiedono un modo per gestire lo stato globale. Esistono molte librerie, ad esempio Redux e MobX, che consentono di eseguire facilmente questa operazione. Salesforce non ne predilige una in particolare e permette di creare app PWA Kit anche senza utilizzarle.

È sempre possibile fornire ai componenti informazioni sullo stato tramite prop. Tuttavia, se si desidera gestire lo stato utilizzando le funzionalità più avanzate di React, consultare questa guida per scoprire approcci alternativi.

Utilizzo delle prop 

La tecnica più semplice per condividere le informazioni sullo stato tra componenti è fornirle a uno di essi tramite prop. Deve trattarsi di un componente di livello superiore rispetto a tutti i componenti che richiedono l’accesso a tali dati. La documentazione di React descrive questa tecnica nel dettaglio e la definisce lifting state up (spostamento in alto dello stato).

Utilizzo di React Context API 

Context API di React consente di rendere facilmente disponibili i dati a un numero elevato di componenti senza doverli trasferire manualmente tramite le prop a ogni livello dell’albero componenti dell’app.

Esempio di React Context 

Ecco un esempio di utilizzo di React Context API con un componente che funge da wrapper di tutti i componenti per fornire loro i dati sullo stato condivisi.

Iniziare creando un componente denominato GlobalState con due oggetti context:

  1. GlobalStateContext: oggetto in cui è possibile memorizzare i dati sullo stato globali.
  2. GlobalDispatchContext: la funzione dispatch, che restituisce uno snapshot aggiornato dello stato globale attraverso una funzione reducer.

Ogni oggetto di contesto viene fornito con uncomponente ” che consente ai componenti di consumo di sottoscrivere le modifiche di contesto. Qui gli oggetti context vengono inizializzati con le prop initialState e dispatch. Queste prop si ottengono collegando lo stato con un reducer mediante l’hook useReducer. Per ulteriori informazioni sugli hook React, incluso l’utilizzo con Context API, vedere la documentazione di riferimento sugli hook React ufficiale.

Ecco in che modo definire e inizializzare un componente che utilizza Context API per memorizzare lo stato globale nell’app dello storefront:

1// app/components/_app-config/index.jsx
2
3import {createContext, useContext} from 'react'
4
5export const GlobalContext = createContext()
6export const useGlobalState = () => useContext(GlobalContext)
7
8const AppConfig = (props) => {
9    const [globalState, setGlobalState] = useState({
10        customer: {name: 'Samantha', registered: true},
11    })
12
13    return (
14        <GlobalContext.Provider value={(globalState, setGlobalState)}>
15            {props.children}
16        </GlobalContext.Provider>
17    )
18}
19
20// app/pages/page/index.jsx
21
22import React, {useContext} from 'react'
23import {useGlobalState} from 'components/_app-config'
24
25export const Page = () => {
26    const {customer, setGlobalState} = useGlobalState()
27
28    // Use setGlobalState to change the global state.
29
30    return <div>{customer.name}</div>
31}

Nel componente speciale AppConfig situato in app/components/_app-config/index.jsx è possibile inizializzare il sistema di gestione dello stato. Qui props.children contiene tutti i componenti dell’app ed è il punto in cui aggiungere il componente GlobalState.

Per ottenere l’oggetto props, è necessario prima inizializzarlo. Utilizzare l’hook React useReducer per creare uno stato collegato al reducer. La funzione useReducer accetta un oggetto initialState e il reducer importato dal componente GlobalState. Successivamente, trasmettere lo stato connesso e una funzione dispatch per modificarlo.

Ad esempio:

1// <PROJECT_DIR>/app/components/_app-config/index.jsx
2
3// Replace your existing React imports
4import React, { useState }, { useReducer }, from "react"
5
6// Import GlobalState component defined in previous example
7import GlobalState, { reducer } from "../global-state"
8
9const initialState = {
10  cart: null
11}
12
13// Combine this with your existing AppConfig component code
14function AppConfig(props) {
15  const [state, dispatch] = useReducer(reducer, initialState);
16
17  return (
18    <GlobalState initialState={state} dispatch={dispatch}>
19      {props.children}
20    </GlobalState>
21  )
22}

A questo punto è possibile concedere a qualsiasi componente l’accesso ai dati di contesto globali, inclusa la possibilità di aggiornarli. Importare GlobalStateContext e GlobalDispatchContext dal componente GlobalState e fornire tali oggetti context al metodo useContext().

Ad esempio:

1import React, {useContext} from 'react'
2import {GlobalStateContext, GlobalDispatchContext, SET_CART_ITEMS} from 'app/components/global-state'
3
4function ExamplePage() {
5    const globalState = useContext(GlobalStateContext)
6    const dispatch = useContext(GlobalDispatchContext)
7
8    // Use this where you want to update the cart data in your global state
9    dispatch({type: SET_CART_ITEMS, payload: cartItems})
10
11    return ( /* render something */ )
12}

Utilizzo di una libreria di gestione dello stato 

È possibile personalizzare l’applicazione in modo da utilizzare una libreria di gestione dello stato sostituendo il componente speciale AppConfig predefinito situato in app/components/_app-config/index.jsx.

Esempio con Redux 

Ecco come impostare Redux per una PWA all’interno di AppConfig. Il componente presenta quattro metodi che devono essere utilizzati:

  1. Il metodo restore, con cui creare lo store Redux con un reducer, uno stato iniziale e qualsiasi middleware.
  2. Il metodo freeze, che consente di congelare il back-end di gestione dello stato per incorporarlo nell’HTML della pagina.
  3. Il metodo extraGetPropsArgs, con cui restituire qualsiasi argomento supplementare che si desidera inserire nei metodi getProps nell’intera app. In questo caso, è possibile restituire lo store Redux come argomento supplementare.
  4. Il metodo render consente di impostare provider di contesto per una libreria di gestione dello stato. Ad esempio, è possibile utilizzarlo per eseguire il wrapping dell’app in un provider Redux.

Ecco un breve esempio che dimostra come utilizzare i metodi di AppConfig per impostare Redux per l’app dello storefront. Oltre ai passaggi descritti, una soluzione completa richiede la creazione dello store con un reducer, uno stato iniziale e qualsiasi middleware obbligatorio.

1// <PROJECT_DIR>/app/components/_app-config/index.jsx
2
3// Combine these imports with your existing imports to include Redux
4imports import React, { useState }, { useReducer }, from "react"
5import PropTypes from "prop-types"
6import { createStore } from "redux"
7import { Provider } from "react-redux"
8
9/**
10 * Combine this code with your existing AppConfig code to use Redux by injecting store object and dispatch function into all getProps() functions.
11 */
12
13class AppConfig extends React.Component {
14  static restore(locals, frozen = {}) {
15    // create your store with a reducer, initial state, and any middleware.
16    const initialState = isServerSide ? {} : frozen
17    locals.store = createStore(reducer, initialState, middlewares)
18  }
19  static freeze(locals) {
20    return locals.store.getState()
21  }
22  static extraGetPropsArgs(locals) {
23    return {
24      store: locals.store,
25      dispatch: locals.store.dispatch
26    }
27  }
28
29  /**
30   * The render function will wrap the app in a Redux provider.
31   */
32  render() {
33    const { children, locals } = this.props
34    return <Provider store={locals.store}>{children}</Provider>
35  }
36}
37
38AppConfig.propTypes = {
39  children: PropTypes.node,
40  locals: PropTypes.object
41}
42
43export default AppConfig