儲存
Framework7 內建輕量級應用程式狀態管理程式庫 - Store。它作為應用程式中所有元件的集中式儲存。
你可以使用特定於程式庫的狀態管理程式庫,例如 Vuex for Vue、Redux for React,並使用內建的 Svelte 儲存功能。但如果需要簡單的功能,Framework7 Store 會是很好的選擇。
建立儲存
首先,我們需要建立儲存。我們為此建立一個獨立的 store.js
檔案
// First import createStore function from Framework7 core
import { createStore } from 'framework7/lite';
// create store
const store = createStore({
// start with the state (store data)
state: {
users: [],
// ...
},
// actions to operate with state and for async manipulations
actions: {
// context object containing store state will be passed as an argument
getUsers({ state }) {
// fetch users from API
fetch('some-url')
.then((res) => res.json())
.then((users) => {
// assign new users to store state.users
state.users = users;
})
},
// ...
},
// getters to retrieve the state
getters: {
// context object containing store state will be passed as an argument
users({ state }) {
return state.users;
}
}
})
// export store
export default store;
在此範例中,我們使用下列 API 函式
createStore(storeParameters)- 建立儲存
- storeParameters - 物件。包含儲存參數的物件
函式傳回已建立的儲存執行個體
儲存參數
現在,我們來看 storeParameters
物件
狀態
state
是包含所有應用程式層級狀態的單一物件,並作為「單一真實來源」。這也表示通常每個應用程式只會有一個儲存。單一狀態樹讓尋找特定狀態片段變得簡單,並讓我們可以輕鬆擷取目前應用程式狀態的快照以進行除錯。
動作
actions
用於修改狀態、進行非同步處理,或呼叫其他儲存動作。動作處理常式會收到一個包含儲存狀態和 dispatch 函式以呼叫其他動作的內容物件。因此,你可以存取 context.store
以存取狀態,或使用 context.dispatch
呼叫其他動作。
作為第二個引數,動作處理常式可能會收到任何自訂資料。
為了保持儲存的反應性,狀態修改應透過指定來完成。例如
// modification of current state property - NOT REACTIVE
state.users.push(...users);
// assignemt to new value - REACTIVE
state.users = [...state.users, ...users];
取得器
getters
處理常式用於從儲存狀態傳回資料。當我們需要根據儲存狀態計算衍生狀態時也很方便,例如過濾項目清單
const store = createStore({
state: {
users: [
{ id: 1, name: '...', registered: true },
{ id: 2, name: '...', registered: false }
]
},
getters: {
registeredUsers: ({ state }) => {
return state.users.filter((user) => user.registered);
}
}
})
取得器處理常式也會收到一個內容物件,但只有儲存狀態。例如,無法從取得器呼叫其他動作。
使用儲存
現在我們已建立儲存,讓我們瞭解如何使用它。
首先,我們需要將已建立的儲存傳遞給主要 App 元件
import React from 'react';
import { App, View } from 'framework7-react';
// import our store
import store from 'path/to/store.js';
export const App = () => {
// ...
return (
{/* pass store to the App's "store" prop */ }
<App store={store}>
<View main>
{/* ... */}
</View>
</App>
)
}
存取儲存和狀態
可透過參照我們建立的儲存體實例,直接存取儲存體(及其狀態)
import store from 'path/to/store.js';
console.log(store.state.users);
或透過存取 Framework7 實例的 store
屬性
import { f7 } from 'framework7-react';
console.log(f7.store.state.users);
發送動作
若要呼叫動作,我們需要呼叫 store.dispatch
方法,並傳入要呼叫的動作名稱。
如果我們有下列儲存體動作
const store = createStore({
// ...
actions: {
// handler receives custom data in second argument
getUsers({ state }, { total }) {
fetch(`some-url?total=${total}`)
.then((res) => res.json())
.then((users) => {
state.users = users;
})
},
},
// ...
})
我們必須呼叫 store.dispatch
方法
import store from 'path/to/store.js';
// call 'getUsers' actions
store.dispatch('getUsers', { total: 10 })
如果我們要在動作處理常式中呼叫另一個動作處理常式
const store = createStore({
// ...
actions: {
setLoading({ state }, isLoading) {
state.isLoading = isLoading;
},
// handler context also contains "dispatch" method
getUsers({ state, dispatch }, { total }) {
// call other action
dispatch('setLoading', true);
fetch(`some-url?total=${total}`)
.then((res) => res.json())
.then((users) => {
state.users = users;
// call other action
dispatch('setLoading', false);
})
},
},
// ...
});
取得器
可將 Getter 值存取為 store.getters
物件的靜態屬性。
const store = createStore({
state: {
count: 10,
},
getters: {
count({ state }) {
return state.count;
},
double({ state }) {
return state.count * 2;
},
},
});
import store from 'path/to/store.js';
const count = store.getters.count;
const double = store.getters.double;
Getter 值是包含含有 Getter 處理常式結果的 .value
屬性的靜態物件,因此
console.log(count.value); // -> 10
console.log(double.value); // -> 20
Getter 與狀態不同,它們旨在具有反應性。因此,當您不需要任何反應性時,您可以直接存取 store.state
,否則請使用 Getter。
與 React 元件一起使用
有一個特殊的 useStore
輔助函式,可用於 React 元件中,以保持儲存體反應性(當狀態/Getter 值變更時自動更新元件)。
useStore(getterName)- 直接傳回 Getter 值,並訂閱狀態更新
- getterName - 字串 - Getter 處理常式的名稱
方法傳回 Getter 處理常式值
如果我們需要從另一個儲存體實例取得 Getter 值,則我們也需要傳遞儲存體
useStore(store, getterName)- 直接傳回 Getter 值,並訂閱狀態更新
- store - 儲存體實例 - 要從中尋找 Getter 的儲存體實例。如果未指定,則會使用傳遞給
<App>
元件的預設儲存體。 - getterName - 字串 - Getter 處理常式的名稱
方法傳回 Getter 處理常式值
如果我們有下列儲存體
const store = createStore({
state: {
users: [],
},
actions: {
getUsers({ state }) {
// ...
},
},
getters: {
users({ state }) {
return state.users;
}
},
});
那麼,例如,我們應該在 React 元件中使用下列程式碼
import React, { useEffect } from 'react';
// import special useStore helper/hook
import { useStore, Page, List, ListItem } from 'framework7-react';
// import store
import store from 'path/to/store.js'
export const UsersPage = () => {
// retrieve "users" getter handler value. Initially empty array
const users = useStore('users');
useEffect(() => {
// load users when component mounted
store.dispatch('getUsers');
}, []);
return (
<Page>
<List>
{users.map((user, index) => (
<ListItem title={user.name} key={index} />
))}
</List>
</Page>
)
}
由於我們使用了 Framework7 的 useStore
輔助函式/hook,因此當使用者載入時,元件將自動更新。
範例
import { createStore } from 'framework7/lite';
const store = createStore({
state: {
loading: false,
users: [],
},
actions: {
getUsers({ state }) {
state.loading = true;
setTimeout(() => {
state.users = ['User 1', 'User 2', 'User 3', 'User 4', 'User 5'];
state.loading = false;
}, 3000);
},
},
getters: {
loading({ state }) {
return state.loading;
},
users({ state }) {
return state.users;
},
},
});
export default store;
import React from 'react';
import {
f7,
useStore,
Page,
Navbar,
Block,
Button,
Preloader,
List,
ListItem,
} from 'framework7-react';
export default () => {
// Subscribe to store getters
const users = useStore('users');
const loading = useStore('usersLoading');
// Call store action
const load = () => f7.store.dispatch('loadUsers');
return (
<Page>
<Navbar title="Store"></Navbar>
<Block strong outlineIos insetMd>
<p>
Framework7 comes with a built-in lightweight application state management library - Store.
It serves as a centralized Store for all the components in an application.
</p>
</Block>
{!users && (
<Block className="text-align-center">
{!loading && (
<Button fill round onClick={load}>
Load Users
</Button>
)}
{loading && <Preloader />}
</Block>
)}
{users && (
<List strong outlineIos dividersIos insetMd>
{users.map((user) => (
<ListItem key={user} title={user} />
))}
</List>
)}
</Page>
);
};