中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Dojo Store 簡介

發布時間:2020-07-11 08:37:11 來源:網絡 閱讀:179 作者:blocklang 欄目:web開發

翻譯自 https://github.com/dojo/framework/blob/master/docs/en/stores/introduction.md

介紹

Dojo store 提供可預測的、一致的狀態容器,內置了對共享狀態管理模式的支持。

Dojo store 包提供了一個集中式存儲,為應用程序提供真正的單一數據源。Dojo 應用程序的操作使用單向數據流;因此,所有應用程序數據遵循相同的生命周期,確保應用程序邏輯是可預測的,且易于理解。

功能 描述
全局數據存儲 應用程序狀態全局存儲在真正的單一數據源中。
單向數據流 可預測的、全局的應用程序狀態管理。
類型安全 對狀態的訪問和修改都受接口的保護。
操作驅動的狀態變更 封裝的、定義良好的狀態修改,可以記錄、撤消和重放。
異步支持 開箱即用的異步命令(command)支持。
操作中間件 在操作前和操作后進行錯誤處理和數據轉換。
簡單的部件集成 提供與 Dojo 部件輕松集成的工具和模式。

基本用法

Dojo 提供了一種響應式架構,能夠持續修改和渲染應用程序的當前狀態。在簡單系統中,這通常發生在部件內部,并且部件可以修改自己的狀態。然而,隨著系統變得越來越復雜,就需要更好的劃分和封裝數據,并隨著快速增長創建一個清晰的隔離。

Store 提供了一個清晰的接口,通過單向數據流對全局對象進行存儲、修改和檢索。Store 中包含對共享模式的支持,如異步數據獲取、中間件和撤銷。Store 及其模式允許部件聚焦于它們的主要角色,即對信息的可視化展示和監聽用戶交互。

store 對象

store 對象存儲整個應用程序全局的、原子的狀態。應該在創建應用程序時創建 store 對象,并使用一個注入器將其定義到 Registry 中。

main.ts

import { registerStoreInjector } from '@dojo/framework/stores/StoreInjector';
import Store from '@dojo/framework/stores/Store';
import { State } from './interfaces';

const store = new Store<State>();
const registry = registerStoreInjector(store);

State 使用接口定義全局存儲的結構。State 中的所有內容都應是可序列化的,即能轉換為 JSON 或從 JSON 轉換回來,這樣的話, Dojo 的虛擬 DOM 系統更容易確定何時更改了數據,從而提高性能。

interfaces.d.ts

interface User {
    id: string;
    name: string;
}

export interface State {
    auth: {
        token: string;
    };
    users: {
        current: User;
        list: User[];
    };
}

上面是一個簡單的示例,定義了 store 的結構,會在本指南的其余示例中使用。

更新 store

使用 Dojo store 時需注意三個核心概念。

  • Operation - 操作 store 所持狀態的指令
  • Command - 執行業務邏輯并返回 operation 的簡單函數
  • Process - 執行一組 command 和表示應用程序的行為

Command 和 operation

要修改 store 中的值,則在執行 process 時,會調用一個 command 函數。command 函數返回要應用到 store 上的一系列 operation。每個 command 都要傳入一個 CommandRequest 參數,它提供了 pathat 函數,會以類型安全的方式生成 Path,也提供了 get 函數來訪問 store 中的狀態,以及提供 payload 對象來為被調用的 process 執行器傳入參數。

Command 工廠

Store 中有一個簡單的封裝函數,用于創建 command,是一個類型安全的工廠函數。

創建 store 工廠:

import { createCommandFactory } from '@dojo/framework/stores/process';
import { State } from './interfaces';

const createCommand = createCommandFactory<State>();

const myCommand = createCommand(({ at, get, path, payload, state }) => {
    return [];
});

createCommand 確保封裝的 command 具有正確的類型,而傳入的 CommandRequest 函數能獲得通過 createCommandFactory 提供的 State 接口的類型。雖然可以手動為 command 設置類型,但本指南中的示例使用 createCommand

path

path 是一個 string,用于描述應用 operation 的位置。path 函數是 CommandRequest 中的一部分,可以在 Command 中訪問。

本示例中,path 描述了 store 中的一個位置。State 與上面 interface.d.ts 中定義的相同。Store 通過 State 接口獲知狀態數據的形狀。

定義一個獲取當前用戶名的 path

const store = new Store<State>();
const { path } = store;

path('users', 'current', 'name');

這個 path 引用的 string 值位于 /users/current/namepath 以類型安全的方式遍歷層次結構,確保只能使用在 State 接口中定義的屬性名。

at

at 函數與 path 函數一起標識數組中的位置。本示例使用了 at 函數。

const store = new Store<State>();
const { at, path } = store;

at(path('users', 'list'), 1);

這個 path 引用的是位于 /user/list 中偏移量為 1User

add operation

用于向對象中添加值或者向數組中插入值。

import { createCommandFactory } from '@dojo/framework/stores/process';
import { State } from './interfaces';
import { add } from '@dojo/framework/stores/state/operations';

const createCommand = createCommandFactory<State>();
const myCommand = createCommand(({ at, get, path, payload, state }) => {
    const user = { id: '0', name: 'Paul' };

    return [add(at(path('users', 'list'), 0), user)];
});

會將 user 插入到用戶列表的起始位置。

remove operation

從對象或數組中移除值。

import { createCommandFactory } from '@dojo/framework/stores/process';
import { State } from './interfaces';
import { add, remove } from '@dojo/framework/stores/state/operations';

const createCommand = createCommandFactory<State>();
const myCommand = createCommand(({ at, get, path, payload, state }) => {
    const user = { id: '0', name: 'Paul' };

    return [
        add(path('users'), {
            current: user,
            list: [user]
        }),
        remove(at(path('users', 'list'), 0))
    ];
});

本示例先為 users 添加一個初始狀態,然后移除 list 中的第一個 user

replace operation

替換值。相當于先 removeadd

import { createCommandFactory } from '@dojo/framework/stores/process';
import { State } from './interfaces';
import { add, replace } from '@dojo/framework/stores/state/operations';

const createCommand = createCommandFactory<State>();
const myCommand = createCommand(({ at, get, path, payload, state }) => {
    const users = [{ id: '0', name: 'Paul' }, { id: '1', name: 'Michael' }];
    const newUser = { id: '2', name: 'Shannon' };

    return [
        add(path('users'), {
            current: user[0],
            list: users
        }),
        replace(at(path('users', 'list'), 1), newUser)
    ];
});

本示例使用 newUser 替換掉 list 中的第二個用戶信息。

get

get 函數會返回 store 在指定 path 位置的值,如果該位置不存在值,則返回 undefined

import { createCommandFactory } from '@dojo/framework/stores/process';
import { State } from './interfaces';
import { remove, replace } from '@dojo/framework/stores/state/operations';

const createCommand = createCommandFactory<State>();

const updateCurrentUser = createCommand(async ({ at, get, path }) => {
    const token = get(path('auth', 'token'));

    if (!token) {
        return [remove(path('users', 'current'))];
    } else {
        const user = await fetchCurrentUser(token);
        return [replace(path('users', 'current'), user)];
    }
});

本示例檢查是否存在身份認證令牌,然后據此更新當前用戶的信息。

payload

payload 是一個對象字面量,當 process 調用 command 時,會將其傳給 command。也可以在構建命令時傳入 payload 的類型。

import { createCommandFactory } from '@dojo/framework/stores/process';
import { State } from './interfaces';
import { remove, replace } from '@dojo/framework/stores/state/operations';

const createCommand = createCommandFactory<State>();

const addUser = createCommand<User>(({ at, path, payload }) => {
    return [add(at(path('users', 'list'), 0), payload)];
});

本示例將 payload 提供的用戶信息添加到 /users/list 的起始位置。

異步 command

command 可以同步執行,也可以異步執行。異步 command 應該返回一個 Promise,以便指出何時完成。每個 command 成功完成后,將自動收集和應用 operation。

Process

Processstore 上按順序執行 command,以修改應用程序的狀態。使用 createProcess 工廠函數創建 process,該函數可傳入一系列 command,以及選擇性的傳入一系列中間件。

創建 process

首先,創建兩個 command,負責獲取用戶令牌,并使用該令牌加載 User。然后創建一個 process 來使用這兩個 command。每一個 process 都應該使用 ID 唯一標識。此 ID 在 store 內部使用。

import { createCommandFactory, createProcess } from "@dojo/framework/stores/process";
import { State } from './interfaces';
import { add, replace } from "@dojo/framework/stores/state/operations";

const createCommand = createCommandFactory<State>();

const fetchUser = createCommand(async ({ at, get, payload: { username, password } }) => {
    const token = await fetchToken(username, password);

    return [
        add(path('auth', 'token'), token);
    ];
}

const loadUserData = createCommand(async ({ path }) => {
    const token = get(path('auth', 'token'));
    const user = await fetchCurrentUser(token);
    return [
        replace(path('users', 'current'), user)
    ];
});

export const login = createProcess('login', [ fetchUser, loadUserData ]);
payload 類型

process 執行器(process executor)的 payload 是從 command 的 payload 類型推斷出來的。如果命令間的 payload 類型不同,則需要顯式定義 process 執行器的 payload 類型。

const createCommand = createCommandFactory<State>();

const commandOne = createCommand<{ one: string }>(({ payload }) => {
    return [];
});

const commandTwo = createCommand<{ two: string }>(({ payload }) => {
    return [];
});

const process = createProcess<State, { one: string; two: string }>('example', [commandOne, commandTwo]);

process(store)({ one: 'one', two: 'two' });

關聯部件和 store

有兩個狀態容器可用于部件:StoreContainerStoreProvider。這些容器將應用程序的 store 與部件關聯起來。當使用函數部件時,也可以創建類型化的 store 中間件。

注意,本節旨在介紹部件和狀態(通過 store 提供的)是如何關聯起來的。有關部件狀態管理的更多信息,請參閱創建部件參考指南。

Store 中間件

當使用基于函數的部件時,createStoreModdleware 幫助函數用于創建類型化的 store 中間件,讓部件能訪問 store。

middleware/store.ts

import createStoreMiddleware from '@dojo/framework/core/middleware/store';
import { State } from '../interfaces';

export default createStoreMiddleware<State>();

widgets/User.tsx

import { create } from '@dojo/framework/core/vdom';
import store from '../middleware/store';
import { State } from '../../interfaces';

const factory = create({ store }).properties();
export const User = factory(function User({ middleware: { store } }) {
    const { get, path } = store;
    const name = get(path('users', 'current', 'name'));

    return <h2>{`Hello, ${name}`}</h2>;
});

此中間件包含一個 executor 方法,用于在 store 上運行 process。

import { create } from '@dojo/framework/core/vdom';
import store from '../middleware/store';
import logout from '../processes/logout';
import { State } from '../../interfaces';

const factory = create({ store }).properties();
export const User = factory(function User({ middleware: { store } }) {
    const { get, path } = store;
    const name = get(path('users', 'current', 'name'));

    const onLogOut = () => {
        store.executor(logout)({});
    };

    return (
        <h2>
            {`Hello, ${name}`}
            <button onclick={onLogOut}>Log Out</button>
        </h2>
    );
});

StoreProvider

StoreProvider 是一個 Dojo 部件,它擁有 renderer,并與 store 關聯。它總是封裝在另一個部件內,因為它無法定義自己的屬性。

widget/User.ts

import { create } from '@dojo/framework/core/vdom';
import { State } from '../../interfaces';

const factory = create().properties();
export const User = factory(function User() {
    return (
        <StoreProvider
            stateKey="state"
            paths={(path) => [path('users', 'current')]}
            renderer={(store) => {
                const { get, path } = store;
                const name = get(path('users', 'current', 'name'));

                return <h2>{`Hello, ${name}`}</h2>;
            }}
        />
    );
});

StoreProviderUser 渲染內容的一部分,并且跟其它 Dojo 部件一樣,提供了自己的 renderer

Container

Container 是一個部件,它完全封裝另一個部件。它使用 getProperties 函數將 store 關聯到部件上。

widget/User.tsx

import { create, tsx } from '@dojo/framework/core/vdom';

interface UserProperties {
    name?: string;
}
const factory = create().properties<UserProperties>();
export const User = factory(function User({ properties }) {
    const { name = 'Stranger' } = properties();
    return <h2>{`Hello, ${name}`}</h2>;
});

widget/User.container.ts

import { createStoreContainer } from '@dojo/framework/stores/StoreContainer';
import { State } from '../interfaces';
import User from './User';

const StoreContainer = createStoreContainer<State>();

const UserContainer = StoreContainer(User, 'state', {
    getProperties({ get, path }) {
        const name = get(path('user', 'current', 'name'));

        return { name };
    }
});

本示例中,UserContainer 封裝了顯示當前用戶名的 UsercreateStoreContainer 是一個封裝器,用于確保 getProperties 中的類型正確。getProperties 負責從 store 中訪問數據,并為部件創建屬性。

StoreContainer 屬性與其封裝部件的屬性是 1:1 映射的。部件的屬性成為 StoreContainer 的屬性,但這些屬性都是可選的。

執行 process

process 只是為一組數據定義了一個執行流。要執行 process,就需要讓 process 基于 store 創建一個執行器。StoreContainerStoreProvider 部件都支持訪問 store。

import { logout } from './processes/logout';
import StoreProvider from '@dojo/framework/stores/StoreProvider';
import { State } from '../../interfaces';
import User from './User';
import { create, tsx } from '@dojo/framework/core/vdom';

const factory = create().properties();
export const UserProvider = factory(function UserProvider() {
    return (
        <StoreProvider
            stateKey="state"
            paths={(path) => [path('users', 'current')]}
            renderer={(store) => {
                const { get, path } = store;
                const name = get(path('users', 'current', 'name'));
                const onLogOut = () => {
                    logout(store)({});
                };

                return <User name={name} onLogOut={onLogOut} />;
            }}
        />
    );
});
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

鄢陵县| 疏勒县| 平潭县| 凤台县| 南雄市| 玉树县| 马边| 梧州市| 永新县| 四会市| 渝北区| 鄱阳县| 三都| 普兰县| 三亚市| 浏阳市| 泗洪县| 旺苍县| 河北区| 邵阳县| 柏乡县| 师宗县| 科技| 宣威市| 都匀市| 德州市| 平凉市| 泾阳县| 南丰县| 栾川县| 确山县| 乡城县| 于田县| 忻城县| 曲水县| 封开县| 绥化市| 都安| 南华县| 禹州市| 北川|