为什么需要状态管理?
-
数据中心化管理。数据流向可预测,暴露出特定函数来操作数据。
-
数据持久化管理。在各个模块中都能共享数据,减少请求或计算。
-
数据同步化管理。实时更新数据,数据发生变更可实时更新状态。
flux 架构
flux 是一种架构思想,用来解决数据结构问题,类似于 MVC 架构,flux 核心理念是单向数据流。
-
View:视图层 UI State。
-
Action:动作行为描述。
-
Dispatcher:事件派发器。
-
Store:数据中心。
用户在 View 层发起一个 Action 对象给 Dispatcher,Dispatcher 接收到 Action 并要求 Store 做相应的更改,Store 做出相对应更新,然后发出一个 changeEvent,View 接收到 changeEvent 事件后,更新页面。
简单实现
发布订阅模式
用于实时更新数据。
-
on:订阅数据
-
emit:发布数据
-
off:取消订阅
const emitter = () => {
const hub = {};
const on = (name, cb) => {
if (!hub[name]) {
hub[name] = [];
}
if (hub[name].indexOf(cb) === -1) {
hub[name].push(cb);
}
};
const emit = (name, data) => {
if (hub[name]) {
hub[name].map(cb => cb(data));
}
};
const off = (name, cb) => {
if (hub[name]) {
const index = hub[name].indexOf(cb);
if (index > -1) {
hub[name].splice(index, 1);
}
}
};
return {on, emit, off};
};
createStore
提供数据操作函数。
-
getState:获取数据
-
setState:更新数据
-
subscribe:订阅数据
-
unsubscribe:取消订阅
const createStore = () => {
const {on, emit, off} = emitter();
const store = {};
const getState = name => clone(store[name]);
const setState = state => {
if (typeof state === 'function') {
state = state(clone(store));
}
const newState = clone(state);
Object.keys(newState).map(key => {
const oldItem = store[key];
const newItem = newState[key];
const item = isObject(newItem) && isObject(oldItem) ? mergeOwnProp(oldItem, newItem) : newItem;
store[key] = item;
});
};
const subscribe = (name, cb) => {
on(name, cb);
return () => off(name, cb);
};
return {getState, setState, subscribe, unsubscribe: off};
};
useStore
import {createStore} from '@huxy/utils';
const store = createStore();
const createContainer = store => (name, initState) => {
const [state, setState] = useState(initState);
const update = useCallback(result => store.setState({[name]: typeof result === 'function' ? result(store.getState(name)) : result}), []);
const subscribe = useCallback(callback => store.subscribe(name, callback), []);
const clean = useCallback((name = name) => store.clean(name), []);
useEffect(() => {
store.subscribe(name, result => setState(result));
}, []);
return [state, update, subscribe, clean];
};
const useStore = createContainer(store);
使用
直接引用:
import {store} from '@huxy/utils';
import {useStore} from '@huxy/use';
自定义 store :
import {createStore, createContainer} from '@huxy/utils';
import {createContainer as createUseContainer} from '@huxy/use';
export const container = createStore();
export const store = createContainer(container);
export const useStore = createUseContainer(container);
store 配置
定义:
import {useStore} from '@huxy/use';
// names
export const langName = 'lang-store';
export const themeName = 'theme-store';
export const menuTypeName = 'menuType-store';
export const i18nsName = 'i18ns-store';
export const userInfoName = 'userInfo-store';
export const permissionName = 'permission-store';
export const routersName = 'routers-store';
// stores
export const useLangStore = initState => useStore(langName, initState);
export const useMenuTypeStore = initState => useStore(menuTypeName, initState);
export const useThemeStore = (initState = {}) => useStore(themeName, initState);
export const useI18nsStore = (initState = {}) => useStore(i18nsName, initState);
export const useUserInfoStore = (initState = {}) => useStore(userInfoName, initState);
export const usePermissionStore = (initState = []) => useStore(permissionName, initState);
export const useRoutersStore = (initState = []) => useStore(routersName, initState);
使用示例:
import {useI18nsStore} from '@app/store/stores';
const Intls = ({keys, children}) => {
const [i18ns] = useI18nsStore();
return (keys && i18ns.getValue(keys)) ?? children ?? '';
};
export default Intls;
使用示例
例如:使用 useStore 来管理已读未读消息,未读消息数量在头部 nav 栏展示,当进入消息列表页面并查看消息时,实时更新 nav 栏未读信息条数。
nav 栏未读消息数量:
const Notify = props => {
const {router} = useRoute();
const [, , subscribe] = useStore('huxy-notify', []);
const [count, setCount] = useState(0);
useEffect(() => {
const getMes = async () => {
const {result} = await apiList.listMessage({current: 1, size: 1000});
const mes = (result?.list ?? []).filter(item => item.active == 0);
setCount(mes.length);
};
const cancelSub = subscribe(result => {
const mes = (result ?? []).filter(item => item.active == 0);
setCount(mes.length);
});
getMes();
return cancelSub;
}, []);
const handleClick = e => {
router.push({
path: '/playground/messages',
state: {tab: 0},
});
};
return (
<a className="notify-item" title="notify" onClick={handleClick}>
<span className="node-icon">
<Badge count={count} size="small">
<BellOutlined />
</Badge>
</span>
</a>
);
};
消息列表:
const MessageList = props => {
const historyState = props.history.getState?.();
const [, setNotify] = useStore('huxy-notify');
const [active, setActive] = useState(historyState?.tab ?? 1);
const handleCheck = async item => {
const items = item ? [item] : selectedRows;
const ids = items.map(v => v._id);
const {code, result, message: msg} = await apiList.markActived({ids});
if (code === 200) {
setNotify(result);
message.success(msg);
setSelectedRows([]);
update({current: 1});
}
};
...
return (
<div className="messages-list">
<TabHeader tabs={tabs} switchTab={switchTab} activekey={active} />
<List {...tableProps} />
</div>
);
};
原文始发于微信公众号(前端道萌):状态管理 – useStore
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/101901.html