hox - 下一代 React 状态管理器

4,006 阅读4分钟

github: github.com/umijs/hox

别着急喷,我已经能想到你为什么会进来看这个文章了,当你看到这个题目的时候,你一定会有几连问:

基于 React Hooks 状态管理器的轮子太多了,你们再造一个有什么意思?

我并不是针对某个轮子,我只想说现有所有的轮子都囿于 reduxunstated-next 的思想,无非就是 actiondispatchreduceruseStoreProviderContext 这些东西,在这些东西上做排列组合。概念一大堆,理解成本不低,用起来还都差不多。

为什么你敢说你们是“下一代”?

hox 够简单,一个 API,几乎无学习成本。够好用,你会用 Hooks,就会用 hox。我想象不到比我们更简单,更好用的轮子怎么造出来?

不想看,不想学,学不动了,咋办?

一个 API,眼睛一瞪就会用,没有任何学习成本。

你们够权威吗?你们会弃坑吗?

hox 的开发者来自蚂蚁金服体验技术部,我们有 umi、dva、antd、antv 等一堆开源软件,团队足够权威。

同时 hox 的思想足够简单,放心用好了。

你们能完全替代 redux,dva 吗?

状态管理器解决的问题都一样,用 hox 完全可以实现所有需求。

hox 介绍

hox 是完全拥抱 React Hooks 的状态管理器,model 层也是用 custom Hook 来定义的,它有以下几个特性:

  • 只有一个 API,简单高效,几乎无需学习成本
  • 使用 custom Hooks 来定义 model,完美拥抱 React Hooks
  • 完美的 TypeScript 支持
  • 支持多数据源,随用随取

下面我们进入正题,hox 怎么用?

定义 Model

任意一个 custom Hook ,用 createModel 包装后,就变成了持久化,且全局共享的数据。

import { createModel } from 'hox';

/* 任意一个 custom Hook */
function useCounter() {
  const [count, setCount] = useState(0);
  const decrement = () => setCount(count - 1);
  const increment = () => setCount(count + 1);
  return {
    count,
    decrement,
    increment
  };
}

export default createModel(useCounter)

使用 Model

createModel 返回值是个 Hook,你可以按 React Hooks 的用法正常使用它。

import { useCounterModel } from "../models/useCounterModel";

function App(props) {
  const counter = useCounterModel();
  return (
    <div>
      <p>{counter.count}</p>
      <button onClick={counter.increment}>Increment</button>
    </div>
  );
}

useCounterModel 是一个真正的 Hook,会订阅数据的更新。也就是说,当点击 "Increment" 按钮时,会触发 counter model 的更新,并且最终通知所有使用 useCounterModel 的组件或 Hook。

其它

  • 基于上面的用法,你肯定已经知道了在 model 之间互相依赖怎么写了,就是单纯的 Hooks 互相依赖,自然而然咯。
import { useCounterModel } from "./useCounterModel";

export function useCounterDouble() {
  const counter = useCounterModel();
  return {
    ...counter,
    count: counter.count * 2
  };
}
  • 只读不订阅更新就更简单了。
import { useCounterModel } from "./useCounterModel";

export function useCounterDouble() {
  const counter = useCounterModel.data;
  return {
    ...counter,
    count: counter.count * 2
  };
}
  • 支持在 class 组件使用哦。

经典用户故事

你肯定遇到过这样的场景:

  • 一开始你把逻辑和数据都放在组件中,每次组件重建,数据都会重置掉。
  • 某一天,你想在把数据存起来,每次组件重建,不会重新刷新数据了。
  • 假设你用的 redux,你需要重新翻译一遍逻辑,完全重写逻辑和数据层,不知道有多痛苦。

如果你用 hox,故事就完全不一样了,你只需要把逻辑和数据层代码直接复制出去就完事了。

  • 比如你开始的代码是这样的:
const CountApp = () => {
  const [count, setCount] = useState(0)
  const decrement = () => setCount(count - 1)
  const increment = () => setCount(count + 1)

  return (
    <div>
      count: {count}
      <button onClick={increment}>自增</button>
      <button onClick={decrement}>自减</button>
    </div>
  )
}
  • 如果你想持久化数据,每次进来想恢复上一次的 count,把逻辑代码复制出来,用 createModel 包一层就完事了。
import { createModel } from 'hox';

/* 逻辑原样复制过来 */
function useCounter() {
  const [count, setCount] = useState(0);
  const decrement = () => setCount(count - 1);
  const increment = () => setCount(count + 1);
  return {
    count,
    decrement,
    increment
  };
}
/* 用 createModel 包一下就行 */
export default createModel(useCounter)
import { useCounterModel } from "./useCounterModel";

export function CountApp() {
  const {count, increment, decrement} = useCounterModel();
  return (
    <div>
      count: {count}
      <button onClick={increment}>自增</button>
      <button onClick={decrement}>自减</button>
    </div>
  )
}

总结

讲完了,核心内容很短,因为足够简单,更多内容可以见 github。如果你觉得 redux、dva 等太难学习,使用繁琐,如果你觉得 unstated-next Provider 嵌套太多,太乱的话,不妨试试 hox,保证会给你全新的开发体验。

hox,下一代 React 状态管理器。

文末再打个广告:umi hooks 最好的 react hooks 逻辑库。