基於 redux 和 react-redux。
倉庫地址:github.com/foca-js/foca
文件地址:foca.js.org
理念
TS First,無TS不程式設計!
特性
- 模組化開發
- 專注 typescript 極致體驗
- 模型自動註冊,匯出即可使用
- 內建 immer 快速處理資料
- 智慧追蹤非同步函式的執行狀態
- 模型支援私有方法
- 可定製的多引擎資料持久化
- 資料隔離,允許同類狀態庫並存
架構圖
線上試玩
使用
定義模型
// File: counterModel.ts
import { defineModel } from 'foca';
const initialState: { count: number } = {
count: 0,
};
// 無須手動註冊到store,直接匯出到react元件中使用
export const counterModel = defineModel('counter', {
// 初始值,必填屬性,其他屬性均可選
initialState,
actions: {
// state可自動提示型別 { count: number }
plus(state, value: number, double: boolean = false) {
// 直接修改狀態
state.count += value * (double ? 2 : 1);
},
minus(state, value: number) {
// 直接返回新狀態
return { count: state.count - value };
},
// 私有方法,只能在模型內部被effect方法呼叫,外部呼叫則TS報錯(屬性不存在)
_clear(state) {
return this.initialState;
},
},
effects: {
// 非同步函式,自動追蹤執行狀態(loading)
async doSomething() {
// 呼叫私有方法
await this._sleep(100);
// 快速處理狀態,對於網路請求的資料十分方便
this.setState({ count: 1 });
this.setState((state) => {
state.count += 1;
});
// 呼叫action函式處理狀態
this.plus(1, true);
// 呼叫effect函式
return this.commonUtil(1);
},
// 普通函式
commonUtil(x: number) {
return x + 1;
},
// 私有方法,只能在模型內部使用,外部呼叫則TS報錯(屬性不存在)
_sleep(duration: number) {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
},
},
hooks: {
// store初始化完成後觸發onInit鉤子
onInit() {
this.plus(1);
console.log(this.state);
},
},
});
在函式元件中使用
import { FC, useEffect } from 'react';
import { useModel, useLoading } from 'foca';
import { counterModel } from './counterModel';
const App: FC = () => {
// count型別自動提示 number
const { count } = useModel(counterModel);
// 僅effects的非同步函式能作為引數傳入,其他函式TS自動報錯
const loading = useLoading(counterModel.doSomething);
useEffect(() => {
counterModel.doSomething();
}, []);
return (
<div onClick={() => counterModel.plus(1)}>
{count} {loading ? 'Loading...' : null}
</div>
);
};
export default App;
在類元件中使用
import { Component } from 'react';
import { connect, getLoading } from 'foca';
import { counterModel } from './counterModel';
type Props = ReturnType<typeof mapStateToProps>;
class App extends Component<Props> {
componentDidMount() {
counterModel.doSomething();
}
render() {
const { count, loading } = this.props;
return (
<div onClick={() => counterModel.plus(1)}>
{count} {loading ? 'Loading...' : null}
</div>
);
}
};
const mapStateToProps = () => {
return {
count: counterModel.state.count,
loading: getLoading(counterModel.doSomething);
};
}
export default connect(mapStateToProps)(App);
希望能成為你下一個專案的狀態管理方案!喜歡就先star一下吧。
倉庫地址:https://github.com/foca-js/foca