流畅的 react 状态管理库,基于redux和react-redux。简洁、极致、高效。
- 模块化开发,导出即可使用
- 专注 TS 极致体验,100%类型提示
- 内置 immer 响应式修改数据
- 支持 computed 计算属性,自动收集依赖
- 支持私有方法
- 自动管理异步函数的 loading 状态
- 可定制的多引擎数据持久化
yarn add foca
import { store } from 'foca';
store.init();
import { defineModel } from 'foca';
const initialState: { count: number } = { count: 0 };
export const counterModel = defineModel('counter', {
initialState,
actions: {
// 支持无限参数
plus(state, value: number, times: number = 1) {
state.count += value * times;
},
minus(state, value: number) {
return { count: state.count - value };
},
},
});
export const counterModel = defineModel('counter', {
initialState,
// 自动收集依赖
computed: {
filled() {
return Array(this.state.count)
.fill('')
.map((_, index) => index)
.map((item) => item * 2);
},
},
});
export const counterModel = defineModel('counter', {
initialState,
actions: {
increment(state) {
state.count += 1;
},
},
effects: {
async incrementAsync() {
await this._sleep(100);
this.increment();
// 也可直接修改状态而不通过actions,仅在内部使用
this.setState({ count: this.state.count + 1 });
this.setState((state) => {
state.count += 1;
});
return 'OK';
},
// 私有方法,外部使用时不会提示该方法
_sleep(duration: number) {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
},
},
});
export const counterModel = defineModel('counter', {
initialState,
events: {
// 模型初始化
onInit() {
console.log(this.state);
},
// 模型数据变更
onChange(prevState, nextState) {},
},
});
import { FC, useEffect } from 'react';
import { useModel, useLoading } from 'foca';
import { counterModel } from './counterModel';
const App: FC = () => {
const count = useModel(counterModel, (state) => state.count);
const loading = useLoading(counterModel.incrementAsync);
useEffect(() => {
counterModel.incrementAsync();
}, []);
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.incrementAsync();
}
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.incrementAsync),
};
};
export default connect(mapStateToProps)(App);
沙盒在线试玩:https://codesandbox.io/s/foca-demos-e8rh3
React 案例仓库:https://github.com/foca-js/foca-demo-web
RN 案例仓库:https://github.com/foca-js/foca-demo-react-native
Taro 案例仓库:https://github.com/foca-js/foca-demo-taro
Nextjs 案例仓库:https://github.com/foca-js/foca-demo-nextjs
仓库 | 版本 | 描述 | 平台 |
---|---|---|---|
axios | 当下最流行的请求库 | React, RN | |
foca-axios | axios 适配器,节流、缓存、重试 | React, RN | |
foca-miniprogram-axios | axios 适配器,节流、缓存、重试 | Taro |
仓库 | 版本 | 描述 | 平台 |
---|---|---|---|
react-native-async-storage | React-Native 持久化引擎 | RN | |
foca-taro-storage | Taro 持久化引擎 | Taro | |
localForage | 浏览器端持久化引擎 | React |
仓库 | 版本 | 描述 | 平台 |
---|---|---|---|
@redux-devtools/extension | 浏览器日志插件 | React, RN | |
react-native-debugger | 日志应用程序 | RN | |
redux-logger | 控制台输出日志 | React, RN, Taro |
答:需要在文件 tsconfig.json 中开启"strict": true
或者"noImplicitThis": true
更多答案请查看文档
开源不易,升级维护框架和解决各种 issue 需要十分多的精力和时间。希望能得到你的支持,让项目处于良性发展的状态。捐赠地址:二维码