儲存
Framework7 內建輕量級應用程式狀態管理函式庫 - Store。它作為應用程式中所有元件的集中式 Store。
你可以使用特定於函式庫的狀態管理函式庫,例如 Vue 的 Vuex、React 的 Redux,並使用內建的 Svelte store 功能。但如果需要簡單的功能,Framework7 Store 會是很好的選擇。
建立 Store
首先,我們需要建立 store。讓我們為此建立一個獨立的 store.js
檔案
// First import createStore function from Framework7 core
import { createStore } from 'framework7';
// 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;
如果你沒有使用模組,則 store.js
檔案會如下所示
// save store as global object
window.store = Framework7.createStore({
state: { /* ... */ },
actions: { /* ... */ },
getters: { /* ... */ },
})
在此範例中,我們使用了下列 API 函式
createStore(storeParameters)- 建立 store
- storeParameters - 物件。包含 store 參數的物件
方法會傳回已建立的 store 執行個體
Store 參數
現在,我們來看一下 storeParameters
物件
狀態
state
是包含所有應用程式層級狀態的單一物件,並作為「單一真實來源」。這也表示你通常只會為每個應用程式有一個 store。單一狀態樹讓尋找特定狀態片段變得簡單,並讓我們可以輕鬆擷取當前應用程式狀態的快照以進行除錯。
動作
actions
用於修改狀態、進行非同步處理,或呼叫其他 store 動作。動作處理常式會收到一個包含 store 狀態和 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];
取得器
取得器
處理常式用於從儲存庫狀態傳回資料。當我們需要根據儲存庫狀態計算衍生狀態時也很方便,例如篩選項目清單
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);
}
}
})
取得器處理常式也會接收一個內容物件,但僅包含儲存庫狀態。例如,無法從取得器呼叫其他動作。
使用儲存庫
現在我們已建立儲存庫,讓我們找出如何使用它。
首先,我們需要將建立的儲存庫傳遞至主應用程式執行個體
// import our store
import store from 'path/to/store.js';
const app = new Framework7({
// pass store to the app's "store" parameter
store,
...
})
存取儲存庫和狀態
可透過參照我們建立的儲存庫執行個體來直接存取儲存庫(及其狀態)
import store from 'path/to/store.js';
console.log(store.state.users);
或透過存取 Framework7 執行個體的 store
屬性
import store from 'path/to/store.js';
const app = new Framework7({
store,
...
})
// somewhere later
console.log(app.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);
})
},
},
// ...
});
取得器
取得器值可作為 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;
取得器值是包含 .value
屬性的靜態物件,其中包含取得器處理常式的結果,因此
console.log(count.value); // -> 10
console.log(double.value); // -> 20
取得器與狀態不同,它們應該是反應靈敏的。因此,當您不需要任何反應靈敏性時,您可以直接存取 store.state
,否則請使用取得器。
與路由元件一起使用
路由元件內容具有 $store
屬性,其中包含下列屬性
state
- 具有儲存庫狀態dispatch
- 用於呼叫動作getters
- 用於存取反應靈敏的取得器處理常式
如果我們有下列儲存庫
const store = createStore({
state: {
users: [],
},
actions: {
getUsers({ state }) {
// ...
},
},
getters: {
users({ state }) {
return state.users;
}
},
});
然後,例如,我們應在路由元件中使用下列內容
<template>
<div class="page">
<ul>
<!-- getter has value in ".value" property -->
${users.value.map((user) => $h`
<li>${user.name}</li>
`)}
</ul>
</div>
</template>
<script>
export default (props, { $store, $on }) => {
// retrieve "users" getter handler value. Initially empty array
const users = $store.getters('users');
$on('pageInit', () => {
// load users on page init
$store.dispatch('getUsers');
});
return $render;
}
</script>
範例
import { createStore } from 'store';
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;
<template>
<div class="page">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="title">Store</div>
</div>
</div>
<div class="page-content">
${users.value.length > 0 ? $h`
<div class="list list-strong list-outline-ios list-dividers-ios inset-md">
<ul>
${users.value.map((user) => $h`
<li class="item-content">
<div class="item-inner">
<div class="item-title">${user}</div>
</div>
</li>
`)}
</ul>
</div>
` : $h`
<div class="block block-strong block-outline-ios inset-md">
<a href="#" class="button button-fill button-round button-preloader ${loading.value ? 'button-loading' : ''}"
@click=${loadUsers}>
<span class="preloader"></span>
<span>Load Users</span>
</a>
</div>
`}
</div>
</div>
</template>
<script>
export default (props, { $store }) => {
const loading = $store.getters.loading;
const users = $store.getters.users;
const loadUsers = () => {
$store.dispatch('getUsers');
};
return $render;
};
</script>