luban-store
v0.0.1
Published
Lightweight library to manage the app state with a centralized store
Downloads
12
Readme
luban-store
Lightweight library to manage the app state with a centralized store
安装
使用 luban-store 需要 React 在 16.8.0 版本以上。
$ npm install luban-store --save
简介
luban-store 是基于 React Hooks 实现的轻量级状态管理框架,具有以下特征:
- 简单、熟悉的 API:不需要额外的学习成本,只需要声明模型,然后
useModel
; - 支持组件 Class 写法:友好的兼容策略可以让老项目享受轻量状态管理的乐趣;
- 集成异步处理:记录异步操作时的执行状态,简化视图中对于等待或错误的处理逻辑;
- 良好的 TypeScript 支持:提供完整的 TypeScript 类型定义,在 VS Code 中能获得完整的类型检查和推断。
快速开始
让我们使用 luban-store 开发一个简单的 Todo 应用,包含以下几个步骤:
第一步:定义模型
export const todos = {
state: {
dataSource: [],
},
actions: {
async fetch(prevState, actions) {
await delay(1000);
const dataSource = [
{ name: 'react' },
{ name: 'vue', done: true},
{ name: 'angular' },
];
return {
...prevState,
dataSource,
}
},
add(prevState, todo) {
return {
...prevState,
dataSource: [
...prevState.dataSource,
todo,
]
};
},
},
};
第二步:创建 Store
import { createStore } from 'luban-store';
import * as models from './models';
export default createStore(models);
第三步:挂载 Store
import React from 'react';
import ReactDOM from 'react-dom';
import store from './store';
const { Provider } = store;
ReactDOM.render(
<Provider>
<App />
</Provider>,
rootEl
);
第四步:消费模型
import React, { useEffect } from 'react';
import store from './store';
const { useModel } = store;
function Todos() {
const [ state, actions ] = useModel('todos');
const { dataSource } = state;
const { fetch, add } = actions;
useEffect(() => {
fetch();
}, []);
function onAdd(event, name) {
if (event.keyCode === 13) {
add({ name: event.target.value });
event.target.value = '';
}
}
return (
<div>
<ul>
{dataSource.map(({ name, done }, index) => (
<li key={index}>
<label>
{done ? <s>{name}</s> : <span>{name}</span>}
</label>
</li>
))}
</ul>
<div>
<input
onKeyDown={onAdd}
placeholder="Press Enter"
/>
</div>
</div>
);
}
API
createStore
createStore(models)
该函数用于创建 Store,将返回一个 Provider 和一些 Hooks。
import { createStore } from 'luban-store';
const store = createStore(models);
const { Provider, useModel, withModel } = store;
入参
models
import { createStore } from 'luban-store'
const counterModel = {
state: {
value: 0
},
};
const models = {
counter: counterModel
};
createStore(models)
state
state: any
:必填
该模型的初始 state。
const model = {
state: { loading: false },
};
actions
actions: { [string]: (prevState, payload, actions, globalActions) => any }
一个改变该模型 state 的所有函数的对象。这些函数采用模型的上一次 state 和一个 payload 作为形参,并且返回模型的下一个状态。
const counter = {
state: 0,
actions: {
add: (prevState, payload) => prevState + payload,
}
};
action 可以是异步的:
const counter = {
actions: {
async addAsync(prevState, payload) => {
await delay(1000);
return prevState + payload;
},
}
};
可以在返回前执行另一个 action 或者另一个模型的 actions:
const user = {
state: {
foo: [],
}
actions: {
like(prevState, payload, actions, globalActions) => {
actions.foo(payload); // 调用本模型的 foo
globalActions.user.foo(payload); // 调用其他模型的 foo
// 做一些操作
return {
...prevState,
};
},
foo(prevState, id) {
// 做一些操作
return {
...prevState,
};
},
}
};
返回值
Provider
Provider(props: { children, initialStates })
将 Store 挂载到 React 应用,以便组件能够通过 Hooks 使用 Store 并与 Store 进行交互。
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'luban-store';
const { Provider } = createStore(models);
ReactDOM.render(
<Provider>
<App />
</Provider>,
rootEl
);
useModel
useModel(name: string): [ state, actions ]
在组件内使用模型实例。
const counter = {
state: {
value: 0
},
actions: {
add: (prevState, payload) => ({...prevState, value: prevState.value + payload}),
}
};
const { userModel } = createStore({ counter });
function FunctionComponent() {
const [ state, actions ] = userModel('name');
state.value; // 0
actions.add(1); // state.value === 1
}
useModelActions
useModelActions(name: string): actions
useModelActions 提供了一种只使用模型的 actions 但不订阅模型更新的的方式。
function FunctionComponent() {
const actions = useModelActions('name');
actions.add(1);
}
useModelActionsState
useModelActionsState(name: string): { [actionName: string]: { isLoading: boolean, error: Error } }
使用 useModelActionsState 来获取模型异步 Action 的执行状态。
function FunctionComponent() {
const actions = useModelActions('name');
const actionsState = useModelActionsState('name');
useEffect(() => {
actions.fetch();
}, []);
actionsState.fetch.isLoading // 异步 Action 是否在执行中
actionsState.fetch.error // 异步 Action 执行是否有误,注意仅当 isLoading 为 false 时这个值才有意义
}
withModel
withModel(name: string, mapModelToProps?: (model: [state, actions]) => Object = (model) => ({ [name]: model }) ): (React.Component) => React.Component
使用 withModel 来连接模型和 Class Component。
class TodoList extends Component {
render() {
const { counter } = this.props;
const [ state, actions ] = counter;
const { dataSource } = state;
state.value; // 0
actions.add(1);
}
}
export default withModel('counter')(TodoList);