存储
框架7附带了一个内置的轻量级应用程序状态管理库 - 存储。它作为应用程序中所有组件的中央存储。
您可以使用特定于库的状态管理库,如Vue的Vuex,React的Redux,以及使用内置的Svelte存储功能。但如果只需要简单的东西,那么框架7存储可能是一个不错的选择。
创建存储
首先,我们需要创建存储。让我们为这个创建一个单独的文件:store.js
在这个例子中,我们使用了以下API函数:
// 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;
createStore(
storeParametersstoreParameters)- 创建存储
- storeParameters - 对象. 带有存储参数的对象
方法返回创建的存储实例
存储参数
现在,让我们看看这个对象:storeParameters
对象:
状态
state
是包含所有应用程序级别状态的单个对象,并作为“单一事实来源”。这也意味着通常您每个应用程序只有一个存储。单个状态树使其能够轻松找到特定的状态片段,并允许我们轻松地为调试目的对当前应用程序状态进行快照。
动作
actions
用于修改状态、异步操作或调用其他存储动作。动作处理程序接收一个包含存储状态和调用其他动作的派发方法的上下文对象。因此,您可以访问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);
或通过访问框架7实例的属性:store
派发动作
import { f7 } from 'framework7-react';
console.log(f7.store.state.users);
派发动作
方法。store.dispatch
如果我们有以下存储动作:
If we have the following store action:
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
,否则使用获取器。
使用 React 组件
有一个特殊的useStore
用于在 React 组件中使用的帮助程序,以保持存储反应性(当状态/获取器值更改时自动更新组件)。
useStore(getterName)- 直接返回获取器值并订阅状态更新
- getterName - 字符串- 获取器处理程序的名称
方法返回获取器处理程序的值
如果我们需要从另一个存储实例获取获取器值,那么我们也需要传递存储:
useStore(store, getterName)- 直接返回获取器值并订阅状态更新
- store - 存储实例- 从中查找获取器的存储实例。如果未指定,则使用传递到
<App>
组件的默认存储。 - getterName - 字符串- 获取器处理程序的名称
方法返回获取器处理程序的值
如果我们有以下存储:
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>
)
}
因为我们使用了框架7useStore
辅助程序/钩子,当用户加载时,组件将自动更新。
示例
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>
);
};