@helux/store-pinia
v5.0.5
Published
Intuitive, type safe, light and flexible Store (based on helux) for React with DevTools support
Downloads
209
Readme
helux-store-pinia
一个优雅的类似 pinia 开发体验的 react 状态管理库,基于 helux 开发
安装
npm i @helux/store-pinia简单例子
const storeCtx = defineStore('Counter', {
// 定义状态(必须)
state: () => ({ count: 0 }),
// 定义带缓存的派生属性(可选)
getters: {
countDouble() {
return this.count * 2;
},
},
// 定义方法修改状态(可选)
actions: {
// 同步方法
addCount(payload: number) {
this.count = payload;
},
// 异步方法
async addCountAsync(paload: number) {
await delay();
this.count = payload;
// or
// this.addCount(payload);
},
},
});复杂例子
创建 store
const storeCtx = defineStore('BookStore', {
// 定义状态(必须)
state: () => ({ list: [] as IBook[], page: 1, size: 10, total: 8, mountCount: 0 }),
// 定义带缓存的派生属性(可选)
getters: {
// 由 state 派生出 totalPlus,上游依赖不变化时此函数不再重复计算
totalPlus() {
return this.total + 1;
},
// 由其他 getters 派生出 totalPlus2,上游依赖不变化时此函数不再重复计算
totalPlus2() {
return this.totalPlus + 100;
},
},
// 定义方法修改状态(可选)
actions: {
// 同步方法
changeTotal(payload: number) {
this.total = payload;
},
// 异步方法
async fetchList(payload: { page: number; size: number }, p2: number) {
console.log(payload.page, payload.size);
await delay();
const { list, total } = await Promise.resolve({
list: [
{ id: '1', name: `state_${Date.now()}`, price: 100 },
{ id: '2', name: `helex_${Date.now()}`, price: 100 },
],
total: 10,
});
this.list = list;
this.total = total;
},
},
// 定义生命周期(可选),包含 willMount mounted willUnmount, 含义见 ILifeCycle 定义,
// lifecycle 方法可访问 actions 里的方法,也可以访问 state 并修改,
// 但是在 actions 里是访问不到 lifecycle 的,只能由框架负责调用,
lifecycle: {
mounted() {
this.mountCount += 1;
},
},
});组件里使用
function Shop() {
const store = storeCtx.useStore();
const ld = storeCtx.useLoading();
// fetchList 的运行状态,如关系其他函数运行状态,可从 ld 继续解构获取到
const { loading, err, ok } = ld.fetchList;
return (
<div>
{loading && <h1>fetching books</h1>}
{err && <h1>{err.message}</h1>}
{ok
&& store.list.map((v) => (
<div key={v.id}>
name:{v.name} price:{v.price}
</div>
))}
<h3>total {store.total}</h3>
<h3>totalPlus {store.totalPlus}</h3>
<button onClick={() => store.fetchList({ page: 1, size: 10 }, 222)}>more</button>
<button onClick={() => store.changeTotal(Date.now())}>change total</button>
<button onClick={() => storeCtx.reset()}>reset</button>
</div>
);
}信号感知
// 细粒度绑定
function Other() {
return (
<div>
total: {$(storeCtx.state.totalPlus)}
<br />
totalPlus2: {$(storeCtx.state.totalPlus2)}
<br />
mountCount: {$(storeCtx.state.mountCount)}
</div>
);
}打印快照
function Snap() {
storeCtx.useStore();
return (
<div style={{ border: '3px solid red', padding: '10px', margin: '12px' }}>
Snap: {JSON.stringify(storeCtx.getSnap())}
<br />
GettersSnap: {JSON.stringify(storeCtx.getGettersSnap())}
<button
onClick={() => {
console.log(storeCtx);
}}
>
see store context
</button>
</div>
);
}添加 redux devtool 插件
import { HeluxPluginDevtool } from '@helux/plugin-devtool';
import { addPlugin } from '@helux/store-pinia';
addPlugin(HeluxPluginDevtool);下图即添加开发差距后的效果
对应代码如下
import { defineStore } from '@helux/store-pinia';
interface IBook {
id: string;
name: string;
price: number;
}
const delay = (ms = 1000) => new Promise((r) => setTimeout(r, ms));
export const storeCtx = defineStore('DefineStoreDemo', {
state: () => ({
list: [] as IBook[],
page: 1,
size: 10,
total: 221,
mountCount: 0,
time: 0,
a: 1,
b: 2,
c: 3,
d: 4,
}),
getters: {
// 由 state 派生出 totalPlus,上游依赖不变化时此函数不再重复计算
totalPlus() {
return this.total + 1;
},
// 由其他 getters 派生出 totalPlus2,上游依赖不变化时此函数不再重复计算
totalPlus2() {
return this.totalPlus + 100;
},
},
actions: {
// 同步方法
changeTotal(payload: number) {
this.total = payload;
},
async otherFn(test?: number, test2?: number) {
await delay(); // ❌ <--- 此处之前无变更,故不会提交
this.a = Date.now();
await delay(); // ✅ <--- 在此之前有数据变更,触发提交
this.b = Date.now();
await delay(); // ✅<--- 在此之前有数据变更,触发提交
this.c = Date.now();
// ✅<--- 结束 action,在此之前有数据变更,触发提交
},
// 异步方法
async fetchList(payload: { page: number; size: number }, p2: number) {
console.log('START fetchList', payload.page, payload.size);
await delay(); // ❌ <--- 此处之前无变更,故不会提交
this.a = Date.now();
await delay(); // <--- ✅ 在此之前有数据变更,触发提交
this.b = Date.now();
await delay(); // <--- ✅ 在此之前有数据变更,触发提交
this.c = Date.now();
await delay(); // <--- ✅ 在此之前有数据变更,触发提交
await this.otherFn(111, 222);
const { list, total } = await Promise.resolve({
list: [
{ id: '1', name: `state_${Date.now()}`, price: 100 },
{ id: '2', name: `helex_${Date.now()}`, price: 100 },
],
total: 10,
});
this.list = list;
this.total = total;
console.log('End fetchList', payload.page, payload.size);
// ✅<--- 结束 action,在此之前有数据变更,触发提交
},
},
});添加自定义插件( 接收来自 helux 内部的各种事件并做对应处理 )
import { addPlugin, IPlugin } from '@helux/store-pinia';
const MyPlugin: IPlugin = {
install(pluginCtx) {
pluginCtx.on('ON_SHARE_CREATED', (dataInfo) => {
// do some staff here
// console.log('ON_SHARE_CREATED', dataInfo);
});
pluginCtx.on('ON_DATA_CHANGED', (dataInfo) => {
// console.log('ON_DATA_CHANGED', dataInfo);
});
},
name: 'MyPlugin',
};
addPlugin(MyPlugin);添加自定义中间件(中间件在变更提交之前按添加顺序依次执行)
import { addMiddleware, Middleware } from '@helux/store-pinia';
const myMiddleware: Middleware = (mid) => {
if (mid.moduleName) {
// 来自某个模块,修改一下时间戳
mid.draft.timestamp = new Date();
}
};
addMiddleware(myMiddleware);