既然我们是通过数据状态来管理视图的,那么在设计初期我们就可以从有限的状态转移来思考业务逻辑。通过思考每个状态对应的数据,状态转移函数,我们可以很清晰的罗列出数据更变逻辑。从数据去控制视图也是现代前端所接触到的MVVM模式。
一个大型应用,我们也会使用Vuex 或 Redux来进行一整个应用的管理。
在平时的业务中,我们会遇到一个痛点是:Vuex,Redux是一个全局状态管理,但我们现在需要在局部需要一个局部状态管理变更,只能使用 mutation
或 dispatch
去提交更改。
如果我们频繁的更新状态,那么我们需要为每一个局部模块编写大量dispatch函数来间接修改全局状态。随着应用的扩充,dispatch文件会越来越臃肿。
那么我们是不是可以使用不同的状态管理工具,来实现局部状态的管理。在局部状态更新完之后,再去用局部更新去更新全局呢?
注:但这也会有一个缺点,局部管理相对独立。有些高度复用的提交函数需要放在全局状态管理上
a. 框架原生组件状态管理
React Hooks + React.createContext
React Hooks提供了useReducer + useContext + Context 可以实现一个小型的状态管理
- // 以下代码就实现了一个能够穿透组件的状态管理
- import React, { useReducer, useContext } from 'react';
- const reducer = (state = 0, { type, …payload }) => {
- switch (type) {
- case 'add':
- return state + 1;
- case 'desc':
- return state – 1;
- default:
- return state;
- }
- }
- const Context = React.createContext();
- const Parent = () => {
- const [state, dispatch] = useReducer(reducer, 0);
- return (
- <>
- <Context.Provider value={{ state, dispatch }}>
- <Son />
- </Context.Provider>
- </>
- )
- }
- function Son() {
- return <Counter />
- }
- function Counter() {
- const { state, dispatch } = useContext(Context);
- return (
- <div>
- <button onClick={() => dispatch({ type: 'desc' })}>-</button>
- {state}
- <button onClick={() => dispatch({ type: 'add' })}>+</button>
- </div>
- )
- }
- export default Parent;
- 复制代码
Vue响应式数据 + vue.Provide/inject
使用vue响应式系统 + provide/inject API来实现一个具有穿透性的局部状态管理
- // Parent.vue
- <template>
- <Son />
- </template>
- <script setup>
- import { provide, reactive, readonly } from "vue";
- import Son from "./Son.vue";
- const data = reactive({
- count: 0,
- });
- const onAdd = () => {
- data.count++;
- };
- const onDesc = () => {
- data.count–;
- };
- provide("store", {
- data: readonly(data), // 只读属性
- onAdd, // 修改函数add
- onDesc, // 修改函数desc
- });
- </script>
- 复制代码
- // Son.vue
- <template>
- <Counter />
- </template>
- <script setup>
- import Counter from "./Counter.vue";
- </script>
- 复制代码
- // Counter.vue
- <template>
- <div>
- <button @click="store.onDesc">-</button>
- {{ store.data.count }}
- <button @click="store.onAdd">+</button>
- </div>
- </template>
- <script setup>
- import { inject } from "vue";
- const store = inject("store", {}); // 穿透读取store
- </script>
- 复制代码