存储
Framework7 附带了一个内置的轻量级应用程序状态管理库 - 存储。它充当应用程序中所有组件的集中式存储。
您可以使用特定于库的状态管理库,例如 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 - object. 具有 store 参数的对象
方法返回创建的 store 实例
Store 参数
现在,让我们看看 storeParameters
对象
状态
state
是一个包含所有应用程序级别状态的单个对象,并充当“单一数据源”。这也意味着通常每个应用程序只有一个 store。单一状态树使得定位特定状态变得简单明了,并且允许我们轻松地获取当前应用程序状态的快照以进行调试。
操作
actions
用于修改状态、进行异步操作或调用其他 store 操作。操作处理程序接收一个上下文对象,该对象包含 store 状态和用于调用其他操作的 dispatch 方法。因此,您可以访问 context.store
以访问状态,或使用 context.dispatch
调用其他操作。
作为第二个参数,操作处理程序可以接收任何自定义数据。
为了保持 store 的响应性,状态修改应该使用赋值来完成。例如
// modification of current state property - NOT REACTIVE
state.users.push(...users);
// assignemt to new value - REACTIVE
state.users = [...state.users, ...users];
获取器
getters
处理程序用于从 store 状态中返回数据。当我们需要根据 store 状态计算派生状态时也很方便,例如过滤项目列表
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);
}
}
})
获取器处理程序也接收一个上下文对象,但该对象仅包含 store 状态。例如,不可能从获取器调用其他操作。
使用 Store
现在,在我们创建了 store 之后,让我们了解如何使用它。
首先,我们需要将创建的 store 传递给主 App 实例
// import our store
import store from 'path/to/store.js';
const app = new Framework7({
// pass store to the app's "store" parameter
store,
...
})
访问 Store 和状态
可以通过引用我们创建的 store 实例直接访问 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
方法。
如果我们有以下 store 操作
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
与状态不同,Getter 旨在实现响应式。因此,当您不需要任何响应式时,您可以直接访问 store.state
,否则请使用 Getter。
在路由组件中使用
路由组件上下文具有 $store
属性,该属性包含以下属性:
state
- 存储状态dispatch
- 调用操作getters
- 访问响应式 Getter 处理程序
如果我们有以下存储:
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>