1.概述
StateStore它是用于ArkUI状态与UI解耦的解决方案,支持全局状态维护,多个组件可以共享以及更新全局状态,将状态管理逻辑从UI组件中分离出来,简化代码结构,提高代码的可维护性。
2.功能特性
1.状态与UI解耦,支持状态全局化操作。
目前现状:在开发复杂应用时,状态与UI的强耦合常常导致代码臃肿、难以维护,尤其是在多个组件需要共享状态时,此时需要组件之间进行层层的传递,难以维护。
StateStore:它将我们的状态管理逻辑从UI组件中抽离出来,实现集中式管理,多个组件可以共享同一个状态对象,而无需通过层层传递数据的方式来实现状态同步,从而大大降低了组件之间的耦合度。
2.支持在子线程中进行状态对象更新。
目前现状:应用开发中,子线程是无法直接修改或操作UI状态,所以子线程在处理完成数据后需要将数据发送给主线程,主线程中来进行UI状态的更新。
StateStore:它内部帮我们封装了状态同步逻辑,我们无需关心,只需要将数据发送给主线程即可,这里也采用了线程间通信对象Sendable协议,它默认线程间对象的传递是通过引用传递,在结合特性1的状态与UI解耦。
3.支持状态更新执行的预处理和后处理。
目前现状:应用开发中想要在状态更新前后插入一些自定义的逻辑,我们需要将代码便在对应的状态更新代码业务逻辑前后,这样会造成代码臃肿,难以维护。
StateStore:它提供了一个一套中间件(Middleware)可以方便的在状态更新前以及后插入自定义的逻辑,并且是解耦。
3.StateStore中核心角色
- StateStore(全局的状态管理实例对象):它是一个共享模块,进程只能加载一次,且不同线程间共享,提供一些初始化等方法。
- Store(全局状态管理仓库):主要维护两个关键方法:getState 和 dispatch(框架的核心方法)
- Reducer(状态处理函数):真正处理状态更新的函数
- Action(事件描述对象):用于描述事件类型,以及事件携带的具体数据。
- Middleware(中间件):提供预处理/后处理函数。
4.源码解析
1.StateStore的共享模块
// 声明当前模块为共享模块,只能导出可Sendable数据
// "use shared" 指令标记一个模块为共享模块
// 注意:共享模块,进程内只会加载一次的模块,且不同线程间共享,StateStore是全局实例对象唯一。
'use shared'
@Sendable
class InnerStateStore {
/**
* 创建状态管理仓库Store。
* @param storeId 仓库ID,每一个仓库的ID是唯一的
* @param state 状态管理数据类 @Observed / @ObservedV2 + @Trace
* @param actions 自定义类型别名Reducer,就是一个函数 (state: T, action: Action) => (() => Promise<void>) | null;
* @param middlewares 状态更新前后的 预处理/后处理实现
* @returns
*/
public createStore<T>(
storeId: string,
state: T,
actions: Reducer<T>,
middlewares?: Middleware<T>[]
): Store<T> {
/**
* 创建一个全局的仓库Store,Store是状态管理的核心,主要向外部提供两个方法
* getState() 获取当前的状态信息
* dispatch 处理来自 UI分发的Action事件
*/
const store = createStore(state, actions, middlewares);
stores.set(storeId, store);
return store;
}
...
/**
* 创建一个事件描述对象
* @param type 标识事件的类型(描述一个事件要做什么),根据类型来处理对应的数据的更新。
* @param payload 事件处理时携带的具体数据
* @returns
*/
public createAction(type: string, payload: ESObject = null):Action {
...
return new Action(type, payload);
}
/**
* 子线程创建一个Sendable格式的Action对象。
*/
public createSendableAction(storeId: string, type: string, payload: lang.ISendable | null = null): SendableAction {
....
const sendableAction = new SendableAction(storeId, type, payload);
return sendableAction;
}
/**
* 主线程接收一个SendableAction对象并触发reducer函数。
* @param sendableAction
*/
public receiveSendableAction<T>(sendableAction: SendableAction) {
const storeId = sendableAction.storeId;
//判断是否存在key为storeId,如果不存在则返回。
if (!stores.hasKey(storeId)) {
StoreLogger.error(StoreError.STORE_NOT_FOUND, 'receiveSendableAction');
return;
}
...
const action: Action = new Action(
sendableAction.type,
sendableAction.payload
)
const store = this.getStore<T>(storeId);
//帮我们调用dispatch来触发UI的更新。
store.dispatch(action);
}
/**
* 将观察对象的多个reducer合并为单个reducer
* @param reducers
* @returns
*/
public combineReducers<T>(
reducers: Record<string, Reducer<ESObject>>
): (state: T, action: Action) => null {
return combineReducers<T>(reducers);
}
}
export let StateStore = new InnerStateStore();
2.StateStore的核心方法createStore解析
- 该方法主要就是实现两个函数。getState 和 dispatch
- getState:获取当前状态对象,该方法实现简单,直接return传入的状态对象。
- dispatch:核心方法,该方法整体步骤:
- 1.初始化中间件,校验以及过滤(过滤符合条件的中间件)
- 2.执行中间件:beforeActions(如果存在)
- 3.执行reducer,真正状态更新的函数
- 4.执行中间件:afterActions(如果存在)
export function createStore<T>(
initialState: T,
reducer: Reducer<T>,
middlewares?: Middleware<T>[]
): Store<T> {
let totalMiddleware = middlewares || [];
//当前的Reducer
let currentReducer = reducer;
//1.getState方法实现简单,只是返回了当前状态对象
const getState = (): T => {
return initialState;
}
//2.dispatch核心
const dispatch = async (action: Action): Promise<void> => {
// 用户传入的 action对象
let currentAction = action;
// 中间件:beforeAction数组
let beforeActions: MiddlewareFuncType<T>[] = [];
// 中间件:afterAction数组
let afterActions: MiddlewareFuncType<T>[] = [];
// 用于校验: 用户传入的动作,确保动作对象的‘ type ’属性存在。
if (currentAction.type === '' && currentAction.type.trim() === '') {
StoreLogger.error(StoreError.INVALID_ACTION_TYPE, 'dispatch');
throw Error('分派失败,类型属性不能为空字符串。');
}
//---------------------- 中间件-> 校验以及过滤 ---------------------
//定义一个局部变量,用于保存符合条件的中间件。
let currentMiddleware: Middleware<T>[] = [];
//是否存在中间件(前后的预处理能力)
if (totalMiddleware.length) {
//过滤符合条件的中间件,并返回新数组
currentMiddleware = totalMiddleware.filter((middleware: Middleware<T>) => {
return middleware.actionType === '' ||
(middleware.actionType !== '' && middleware.actionType === action.type);
});
// 分别存储中间件beforeAction和afterAction
if (currentMiddleware && currentMiddleware.length > 0) {
currentMiddleware.forEach((middleware: Middleware<T>) => {
// 向数组末尾添加一个元素
beforeActions.push(middleware.beforeAction);
// 向数组开头添加一个元素
afterActions.unshift(middleware.afterAction);
})
}
}
//---------------------- 中间件-> 校验以及过滤 ---------------------
// 将中间件修改的操作类型存储在reducer中。
const resetAction: Action[] = [];
try {
//---------------------- 中间件->预处理操作 ---------------------
// 执行中间件 beforeAction 的逻辑
try {
if (beforeActions.length > 0) {
const shouldContinue = await executeMiddleware<T>(initialState, currentAction, beforeActions, resetAction);
//如果返回false
if (!shouldContinue) {
return; //函数会直接退出,中断代码,下方reducer将不会执行。
}
}
} catch (e) {
StoreLogger.error('Catch errors during the execution of the beforeAction in the middleware %s',
`message is ${e.message}`);
return;
}
// 如果中间件beforeAction,返回一个新的动作(Action),修改reducer将要执行的动作类型。(相当于篡改了用户的动作Action)
if (resetAction.length === 1) {
currentAction = resetAction[0];
}
//---------------------- 中间件->预处理操作 ---------------------
/**
* 触发reducer
* 参数1:状态对象
* 参数2:action对象,type用于描述事件动作
*/
const result = currentReducer(initialState, currentAction);
//---------------------- 中间件->后处理操作 ---------------------
// reducer返回一个函数来执行异步操作。 相当于在reducer中 return async() => {}
if (typeof result === 'function') {
let func: AsyncFunction = result as AsyncFunction;
//执行函数成功后,开始执行中间件的afterAction后处理操作。
func().then(async () => {
try {
if (afterActions.length > 0) {
const shouldContinue = await executeMiddleware<T>(initialState, currentAction, afterActions, resetAction);
if (!shouldContinue) {
return;
}
}
} catch (err) {
StoreLogger.error('Catch errors during the execution of the afterAction in the middleware %s',
`message is ${err.message}`);
}
})
} else {
//没有返回函数的情况,依然需要处理,中间件的afterAction后处理操作
if (afterActions.length > 0) {
const shouldContinue = await executeMiddleware<T>(initialState, currentAction, afterActions, resetAction);
if (!shouldContinue) {
return;
}
}
}
//---------------------- 中间件->后处理操作 ---------------------
} catch (outerErr) {
StoreLogger.error('Catch errors during the execution of the dispatch in the middleware %s',
`message is ${outerErr.message}`);
}
return;
}
return {
getState,
dispatch,
}
}
export interface Store<T> {
/**
* 获取观察状态对象
*/
getState: () => T;
/**
* 派发一个动作。这是触发状态变化的方式。
*/
dispatch: Dispatch;
}
//自定义的函数类型别名
export type Dispatch = (action: Action) => Promise<void>;
//自定义函数类型别名,接收两个参数(state: T, action: Action) 并返回 无参数Promise函数 或者 null
export type Reducer<T> = (state: T, action: Action) => (() => Promise<void>) | null;
//事件描述对象
export class Action {
readonly type: string; //事件类型
payload: ESObject; //事件携带具体的数据
...
setPayload(payload: ESObject) {
this.payload = payload
return this;
}
}
/**
* 中间件
* beforeAction: 中间件前置处理,返回值为联合函数,MiddlewareStatus | Action,
* afterAction: 中间件后置处理,返回值为联合函数,MiddlewareStatus | Action,
*/
export abstract class Middleware<T> {
/**
* 如果定义了actionType,中间件将只在以下情况下执行
* 对应调度的Action的type相同情况会执行。
*/
actionType: string = '';
abstract beforeAction: MiddlewareFuncType<T>;
abstract afterAction: MiddlewareFuncType<T>;
}
/**
* 定义的类型别名MiddlewareFuncType
*/
export type MiddlewareFuncType<T> = (
(state: T, action: Action) => MiddlewareStatus | Action
) | (
(state: T, action: Action) => Promise<MiddlewareStatus | Action >
)
/**
* 中间件的状态
*/
export enum MiddlewareStatus {
DROP, // Interrupt
NEXT, // continue
}
-
StateStore没有中间件时执行流程图
image.png -
StateStore整体的执行流程图
image.png
3.StateStore的中间件的处理解析
- 这里需要注意中间件的返回值
- MiddlewareStatus.DROP:函数会直接退出,循环也随之停止执行。
- MiddlewareStatus.NEXT:继续执行。
- Action:相当于篡改用户的Action行为。
/**
* 中间件中beforeAction和afterAction函数的执行逻辑
*/
export const executeMiddleware = async <T>(
state: T,
action: Action,
subscribers: MiddlewareFuncType<T>[],
resetAction: Action[]
): Promise<boolean> => {
//用户传入的action对象
let currentAction = action;
//遍历当前Store中所有的中间件的beforeAction集合
for (const sub of subscribers) {
// 重置在中间件中传递的操作。
if (resetAction.length === 1) currentAction = resetAction[0];
//执行beforeAction
const result: MiddlewareStatus | Action = await sub(state, currentAction);
if (result === MiddlewareStatus.DROP) {
/**
* 1. 如果前一个动作函数返回 MiddlewareStatus.DROP,函数会直接退出,循环也随之停止执行。
*/
return false;
} else if (isAction(result)) {
/**
* 2.如果前一个中间件函数返回一个动作对象,后续中间件函数和reducer将执行返回的动作对象。
* 相当于篡改了我们用户传入的Action对象。
*/
resetAction[0] = result as Action;
}
}
// 3. 如果前面的函数返回 MiddlewareStatus.NEXT,继续执行。
return true;
}
4.StateStore的支持在子线程中进行状态对象更新解析
- 这里采用的是Sendable协议,上面也有介绍,可以进行查看。
- 核心主要是StateStore的receiveSendableAction方法,帮我们封装好了触发状态更新的函数。
public receiveSendableAction<T>(sendableAction: SendableAction) {
const storeId = sendableAction.storeId;
...
//1.将SendableAction换为Action
const action: Action = new Action(
sendableAction.type,
sendableAction.payload
)
//2.根据storeId获取对应的Store对象
const store = this.getStore<T>(storeId);
//3.触发Store的dispatch,从而触发状态的更新。
store.dispatch(action);
}
5.StateStore与传统状态管理对比
| 特性 | 传统状态管理(@State,@Prop等) | State(全局状态管理) |
|---|---|---|
| 生命周期 | 父子组件内 | 全局应用层级 |
| 状态共享 | 组件之间传递 | 全局的Store仓库,获取状态对象 |
| 状态修改 | 组件内对状态装饰器的变量赋值 | 组件内调用Store的dispatch方法发送一个事件对象 |
| 维护性 | 低(状态分散在各个组件内) | 高(Reducer函数集中管理) |
| 使用场景 | 单组件/父子组件状态共享 | 1.跨组件状态共享 2.支持中间并且解耦 3.简化子线程同步状态 |

