翻譯自:https://github.com/dojo/framework/blob/master/docs/en/stores/supplemental.md
龍華網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),龍華網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為龍華上千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營銷網(wǎng)站建設(shè)要多少錢,請找那個(gè)售后服務(wù)好的龍華做網(wǎng)站的公司定做!State
對(duì)象在現(xiàn)代瀏覽器中,state
對(duì)象是作為 CommandRequest
的一部分傳入的。對(duì) state
對(duì)象的任何修改都將轉(zhuǎn)換為相應(yīng)的 operation,然后應(yīng)用到 store 上。
import { createCommandFactory } from '@dojo/framework/stores/process';
import { State } from './interfaces';
import { remove, replace } from '@dojo/framework/stores/state/operations';
const createCommand = createCommandFactory();
const addUser = createCommand(({ payload, state }) => {
const currentUsers = state.users.list || [];
state.users.list = [...currentUsers, payload];
});
注意,IE 11 不支持訪問 state,如果嘗試訪問將立即拋出錯(cuò)誤。
StoreProvider
StoreProvider 接收三個(gè)屬性
renderer
: 一個(gè)渲染函數(shù),已將 store 注入其中,能訪問狀態(tài)并向子部件傳入 process。stateKey
: 注冊狀態(tài)時(shí)使用的 key 值。paths
(可選): 將此 provider 連接到狀態(tài)的某一局部上。StoreProvider
有兩種方法觸發(fā)失效并促使重新渲染。
paths
屬性來注冊 path
,以確保只有相關(guān)狀態(tài)變化時(shí)才會(huì)失效。path
時(shí),store 中的 任何 數(shù)據(jù)變化都會(huì)引起失效。Process
Process
有一個(gè)執(zhí)行生命周期,它定義了所定義行為的流程。
before
中間件after
中間件使用可選的 before
和 after
方法在 process 的前后應(yīng)用中間件。這允許在 process 所定義行為的前和后加入通用的、可共享的操作。
也可以在列表中定義多個(gè)中間件。會(huì)根據(jù)中間件在列表中的順序同步調(diào)用。
before
中間件塊能獲取傳入的 payload
和 store
的引用。
middleware/beforeLogger.ts
const beforeOnly: ProcessCallback = () => ({
before(payload, store) {
console.log('before only called');
}
});
after
中間件塊能獲取傳入的 error
(如果發(fā)生了錯(cuò)誤的話)和 process 的 result
。
middleware/afterLogger.ts
const afterOnly: ProcessCallback = () => ({
after(error, result) {
console.log('after only called');
}
});
result
實(shí)現(xiàn)了 Proce***esult
接口,以提供有關(guān)應(yīng)用到 store 上的變更信息和提供對(duì) store 的訪問。
executor
- 允許在 store 上運(yùn)行其他 processstore
- store 引用operations
- 一組應(yīng)用的 operationundoOperations
- 一組 operation,用來撤銷所應(yīng)用的 operationapply
- store 上的 apply 方法payload
- 提供的 payloadid
- 用于命名 process 的 idStore
有一個(gè) onChange(path, callback)
方法,該方法接收一個(gè)或一組 path,并在狀態(tài)變更時(shí)調(diào)用回調(diào)函數(shù)。
main.ts
const store = new Store();
const { path } = store;
store.onChange(path('auth', 'token'), () => {
console.log('new login');
});
store.onChange([path('users', 'current'), path('users', 'list')], () => {
// Make sure the current user is in the user list
});
Store
中還有一個(gè) invalidate
事件,store 變化時(shí)就觸發(fā)該事件。
main.ts
store.on('invalidate', () => {
// do something when the store's state has been updated.
});
首次創(chuàng)建 store 時(shí),它為空。然后,可以使用一個(gè) process 為 store 填充初始的應(yīng)用程序狀態(tài)。
main.ts
const store = new Store();
const { path } = store;
const createCommand = createCommandFactory();
const initialStateCommand = createCommand(({ path }) => {
return [add(path('auth'), { token: undefined }), add(path('users'), { list: [] })];
});
const initialStateProcess = createProcess('initial', [initialStateCommand]);
initialStateProcess(store)({});
Dojo store 使用 patch operation 跟蹤底層 store 的變化。這樣,Dojo 就很容易創(chuàng)建一組 operation,然后撤銷這組 operation,以恢復(fù)一組 command 所修改的任何數(shù)據(jù)。undoOperations
是 Proce***esult
的一部分,可在 after
中間件中使用。
當(dāng)一個(gè) process 包含了多個(gè)修改 store 狀態(tài)的 command,并且其中一個(gè) command 執(zhí)行失敗,需要回滾時(shí),撤銷(Undo) operation 非常有用。
undo middleware
const undoOnFailure = () => {
return {
after: () => (error, result) {
if (error) {
result.store.apply(result.undoOperations);
}
}
};
};
const process = createProcess('do-something', [
command1, command2, command3
], [ undoOnFailure ])
在執(zhí)行時(shí),任何 command 出錯(cuò),則 undoOnFailure
中間件就負(fù)責(zé)應(yīng)用 undoOperations
。
需要注意的是,undoOperations
僅適用于在 process 中完全執(zhí)行的 command。在回滾狀態(tài)時(shí),它將不包含以下任何 operation,這些狀態(tài)的變更可能是異步執(zhí)行的其他 process 引起的,或者在中間件中執(zhí)行的狀態(tài)變更,或者直接在 store 上操作的。這些用例不在 undo 系統(tǒng)的范圍內(nèi)。
樂觀更新可用于構(gòu)建響應(yīng)式 UI,盡管交互可能需要一些時(shí)間才能響應(yīng),例如往遠(yuǎn)程保存資源。
例如,假使正在添加一個(gè) todo 項(xiàng),通過樂觀更新,可以在向服務(wù)器發(fā)送持久化對(duì)象的請求之前,就將 todo 項(xiàng)添加到 store 中,從而避免尷尬的等待期或者加載指示器。當(dāng)服務(wù)器響應(yīng)后,可以根據(jù)服務(wù)器操作的結(jié)果成功與否,來協(xié)調(diào) store 中的 todo 項(xiàng)。
在成功的場景中,使用服務(wù)器響應(yīng)中提供的 id
來更新已添加的 Todo
項(xiàng),并將 Todo
項(xiàng)的顏色改為綠色,以指示已保存成功。
在出錯(cuò)的場景中,可以顯示一個(gè)通知,說明請求失敗,并將 Todo
項(xiàng)的顏色改為紅色,同時(shí)顯示一個(gè)“重試”按鈕。甚至可以恢復(fù)或撤銷添加的 Todo 項(xiàng),以及在 process 中發(fā)生的其他任何操作。
const handleAddTodoErrorProcess = createProcess('error', [ () => [ add(path('failed'), true) ]; ]);
const addTodoErrorMiddleware = () => {
return {
after: () => (error, result) {
if (error) {
result.store.apply(result.undoOperations);
result.executor(handleAddTodoErrorProcess);
}
}
};
};
const addTodoProcess = createProcess('add-todo', [
addTodoCommand,
calculateCountsCommand,
postTodoCommand,
calculateCountsCommand
],
[ addTodoCallback ]);
addTodoCommand
- 在應(yīng)用程序狀態(tài)中添加一個(gè) todo 項(xiàng)calculateCountsCommand
- 重新計(jì)算已完成的待辦項(xiàng)個(gè)數(shù)和活動(dòng)的待辦項(xiàng)個(gè)數(shù)postTodoCommand
- 將 todo 項(xiàng)提交給遠(yuǎn)程服務(wù),并使用 process 的 after
中間件在發(fā)生錯(cuò)誤時(shí)執(zhí)行進(jìn)一步更改
calculateCountsCommand
- postTodoCommand
成功后再運(yùn)行一次在某些情況下,在繼續(xù)執(zhí)行 process 之前,最好等后端調(diào)用完成。例如,當(dāng) process 從屏幕中刪除一個(gè)元素時(shí),或者 outlet 發(fā)生變化要顯示不同的視圖,恢復(fù)觸發(fā)這些操作的狀態(tài)可能會(huì)讓人感到很詭異(譯注:數(shù)據(jù)先從界面上刪掉了,因?yàn)楹笈_(tái)刪除失敗,過一會(huì)數(shù)據(jù)又出現(xiàn)在界面上)。
因?yàn)?process 支持異步 command,只需簡單的返回 Promise
以等待結(jié)果。
function byId(id: string) {
return (item: any) => id === item.id;
}
async function deleteTodoCommand({ get, payload: { id } }: CommandRequest) {
const { todo, index } = find(get('/todos'), byId(id));
await fetch(`/todo/${todo.id}`, { method: 'DELETE' });
return [remove(path('todos', index))];
}
const deleteTodoProcess = createProcess('delete', [deleteTodoCommand, calculateCountsCommand]);
Process
支持并發(fā)執(zhí)行多個(gè) command,只需將這些 command 放在一個(gè)數(shù)組中即可。
process.ts
createProcess('my-process', [commandLeft, [concurrentCommandOne, concurrentCommandTwo], commandRight]);
本示例中,commandLeft
先執(zhí)行,然后并發(fā)執(zhí)行 concurrentCommandOne
和 concurrentCommandTwo
。當(dāng)所有的并發(fā) command 執(zhí)行完成后,就按需應(yīng)用返回的結(jié)果。如果任一并發(fā) command 出錯(cuò),則不會(huì)應(yīng)用任何操作。最后,執(zhí)行 commandRight
。
當(dāng)實(shí)例化 store 時(shí),會(huì)默認(rèn)使用 MutableState
接口的實(shí)現(xiàn)。在大部分情況下,默認(rèn)的狀態(tài)接口都經(jīng)過了很好的優(yōu)化,足以適用于常見情況。如果一個(gè)特殊的用例需要另一個(gè)實(shí)現(xiàn),則可以在初始化時(shí)傳入該實(shí)現(xiàn)。
const store = new Store({ state: myStateImpl });
MutableState
API任何 State
實(shí)現(xiàn)都必須提供四個(gè)方法,以在狀態(tài)上正確的應(yīng)用操作。
get<S>(path: Path<M, S>): S
接收一個(gè) Path
對(duì)象,并返回當(dāng)前狀態(tài)中該 path 指向的值at<S extends Path<M, Array<any>>>(path: S, index: number): Path<M, S['value'][0]>
返回一個(gè) Path
對(duì)象,該對(duì)象指向 path 定位到的數(shù)組中索引為 index
的值path: StatePaths<M>
以類型安全的方式,為狀態(tài)中給定的 path 生成一個(gè) Path
對(duì)象apply(operations: PatchOperation<T>[]): PatchOperation<T>[]
將提供的 operation 應(yīng)用到當(dāng)前狀態(tài)上ImmutableState
Dojo Store 通過 Immutable 為 MutableState 接口提供了一個(gè)實(shí)現(xiàn)。如果對(duì) store 的狀態(tài)做頻繁的、較深層級(jí)的更新,則這個(gè)實(shí)現(xiàn)可能會(huì)提高性能。在最終決定使用這個(gè)實(shí)現(xiàn)之前,應(yīng)先測試和驗(yàn)證性能。
Using Immutable
import State from './interfaces';
import Store from '@dojo/framework/stores/Store';
import Registry from '@dojo/framework/widget-core/Registry';
import ImmutableState from '@dojo/framework/stores/state/ImmutableState';
const registry = new Registry();
const customStore = new ImmutableState();
const store = new Store({ store: customStore });
Dojo Store 提供了一組工具來使用本地存儲(chǔ)(local storage)。
本地存儲(chǔ)中間件監(jiān)視指定路徑上的變化,并使用 collector
中提供的 id
和 path 中定義的結(jié)構(gòu),將它們存儲(chǔ)在本地磁盤上。
使用本地存儲(chǔ)中間件:
export const myProcess = createProcess(
'my-process',
[command],
collector('my-process', (path) => {
return [path('state', 'to', 'save'), path('other', 'state', 'to', 'save')];
})
);
來自 LocalStorage
中的 load
函數(shù)用于與 store 結(jié)合
與狀態(tài)結(jié)合:
import { load } from '@dojo/framework/stores/middleware/localStorage';
import { Store } from '@dojo/framework/stores/Store';
const store = new Store();
load('my-process', store);
注意,數(shù)據(jù)要能夠被序列化以便存儲(chǔ),并在每次調(diào)用 process 后都會(huì)覆蓋數(shù)據(jù)。此實(shí)現(xiàn)不適用于不能序列化的數(shù)據(jù)(如 Date
和 ArrayBuffer
)。
Dojo Store 使用 operation 來更改應(yīng)用程序的底層狀態(tài)。這樣設(shè)計(jì) operation,有助于簡化對(duì) store 的常用交互,例如,operation 將自動(dòng)創(chuàng)建支持 add
或 replace
operation 所需的底層結(jié)構(gòu)。
在未初始化的 store 中執(zhí)行一個(gè)深度 add
:
import Store from '@dojo/framework/stores/Store';
import { add } from '@dojo/framework/stores/state/operations';
const store = new Store();
const { at, path, apply } = store;
const user = { id: '0', name: 'Paul' };
apply([add(at(path('users', 'list'), 10), user)]);
結(jié)果為:
{
"users": {
"list": [
{
"id": "0",
"name": "Paul"
}
]
}
}
即使?fàn)顟B(tài)尚未初始化,Dojo 也能基于提供的 path 創(chuàng)建出底層的層次結(jié)構(gòu)。這個(gè)操作是安全的,因?yàn)?TypeScript 和 Dojo 提供了類型安全。這允許用戶很自然的使用 store 所用的 State
接口,而不需要顯式關(guān)注 store 中保存的數(shù)據(jù)。
當(dāng)需要顯式使用數(shù)據(jù)時(shí),可以使用 test
操作或者通過獲取底層數(shù)據(jù)來斷言該信息,并通過編程的方式來驗(yàn)證。
本示例使用 test
操作來確保已初始化,確保始終將 user
添加到列表的末尾:
import Store from '@dojo/framework/stores/Store';
import { test } from '@dojo/framework/stores/state/operations';
const store = new Store();
const { at, path, apply } = store;
apply([test(at(path('users', 'list', 'length'), 0))]);
本示例通過編程的方式,確保 user
總是作為最后一個(gè)元素添加到列表的末尾:
import Store from '@dojo/framework/stores/Store';
import { add, test } from '@dojo/framework/stores/state/operations';
const store = new Store();
const { get, at, path, apply } = store;
const user = { id: '0', name: 'Paul' };
const pos = get(path('users', 'list', 'length')) || 0;
apply([
add(at(path('users', 'list'), pos), user),
test(at(path('users', 'list'), pos), user),
test(path('users', 'list', 'length'), pos + 1)
]);
禁止訪問狀態(tài)的根節(jié)點(diǎn),如果訪問將會(huì)引發(fā)錯(cuò)誤,例如嘗試執(zhí)行 get(path('/'))
。此限制也適用于 operation;不能創(chuàng)建一個(gè)更新狀態(tài)根節(jié)點(diǎn)的 operation。@dojo/framewok/stores
的最佳實(shí)踐是鼓勵(lì)只訪問 store 中最小的、必需的部分。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。