此文已使用 Salesforce 機器翻譯系統翻譯。更多詳細資料請參見此處。
有些網店應用程式需要能夠管理全域狀態的方法。有許多狀態管理庫可以協助您達成這個目標,例如 Redux 和 MobX。Salesforce 並不為任何特定的狀態管理庫背書,您無需使用任何狀態管理庫,也能建置 PWA Kit 應用程式。
您可以透過 Props 向元件提供狀態資訊,但若您想使用 React 更為進階的功能來管理狀態,這份指南也會介紹其他方法。
在元件之間分享狀態最簡單的方式,就是透過 Props 向元件提供狀態資訊。此元件必須是所有需要存取狀態資料的元件的父代元件。React 文件詳細說明了此技術,並將其稱為提升狀態。
React 的 Context API 簡化了將資料提供給大量元件的過程,而無需在應用程式元件樹的每個層級透過 Props 手動傳遞資料。
以下範例說明如何將 React Context API 與元件一起使用,來作為所有元件的包裝,為它們提供共用的狀態資料。
首先,先建立一個稱為 GlobalState 的元件,其中有兩個內容物件:
GlobalStateContext:您可在此儲存全域狀態資料。GlobalDispatchContext:您的 dispatch 函式,可透過 reducer 函式傳回已更新的全域狀態快照。每個上下文物件都帶有一個 『initialState 和dispatch 進行初始化。當您使用 useReducer Hook 連結狀態至 reducer 時,會獲得這些 Props。如需進一步瞭解 React Hook 的相關資訊,包括如何將它們與 Context API 一起使用,請參閱官方 React Hook 參考文件。
以下說明如何定義並初始化使用 Context API 在網店應用程式中儲存全域狀態的元件:
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}位於 app/components/_app-config/index.jsx 的 AppConfig 特殊元件是您可以初始化狀態管理系統的地方。在此,props.children 包含您應用程式的所有元件,因此您要在此處新增 GlobalState 元件。
要獲得 Props 物件,您必須先將其初始化。使用 React Hook useReducer 來建立連結狀態至 reducer。useReducer 函式會接受 initialState 物件和從 GlobalState 元件匯入的 reducer。接下來,請傳入已連結狀態和 dispatch 函式來修改該狀態。
舉例來說:
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}現在,您可以讓任何元件存取全域 Context 資料,包括進行更新的能力。從 GlobalState 元件匯入 GlobalStateContext 和 GlobalDispatchContext,並提供這些 Context 物件給 useContext() 方法。
舉例來說:
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}您可以覆寫位於 app/components/_app-config/index.jsx 的預設 AppConfig 特殊元件,來自訂應用程式以使用狀態管理庫。
以下是在 AppConfig 內為您的 PWA 設定 Redux 的方式。此元件有四種您需要使用的方法:
restore 方法是您使用 reducer、初始狀態和任何中介軟體建立 Redux 儲存區的地方。。freeze 方法可讓您凍結狀態管理後端,以嵌入到頁面 HTML。extraGetPropsArgs 方法是您可以傳回任何您想在整個應用程式的 getProps 方法中插入的額外引數的地方。在這種情況下,我們可以將 Redux 儲存區作為額外引數傳回。render 方法可讓您為狀態管理庫設定 context 提供器。舉例來說,您可以使用它來將應用程式包裝在 Redux 提供器內。以下是簡短範例,說明如何使用 AppConfig 方式為您的網店應用程式設定 Redux。除了我們於此處說明的步驟之外,完整的解決方案還需要您使用 reducer、初始狀態和任何所需的中介軟體來建立您的儲存區。
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