Skip to content
/ heo Public

简单、优雅的 React hooks 状态管理方案

License

Notifications You must be signed in to change notification settings

MinJieLiu/heo

Repository files navigation

Heo

简单、优雅的 React hooks 状态管理方案

CI coveralls npm size

  • 自动优化 完全按需 rerender,专注性能
  • React Hooks 适用于 React Hooks 组件
  • 1KB min+gz
  • 简单 只需会 React Hooks,即可上手
  • TypeScript 编写 完备的类型提示,轻松编写代码
  • 容易集成 可渐进式引入,与其他状态管理共存
  • 通用 组件、模块、应用以及服务端渲染
  • 灵活 基于 Context,轻松组合 Provider
  • 轻松迁移 它基于自定义 Hooks 创建

安装

npm i heo

Example

import { useState, useCallback, memo } from 'react';
import { createStore } from 'heo';

const CounterStore = createStore(() => {
  const [count, setCount] = useState(0);

  // 函数需要记忆化后导出
  const increment = useCallback(() => setCount(prev => prev + 1), []);
  const decrement = useCallback(() => setCount(prev => prev - 1), []);

  return {
    count,
    increment,
    decrement,
  };
});

const Counter = memo(() => {
  // 只有在 count 变化后才会触发 rerender
  const { count, increment } = CounterStore.usePicker();

  return (
    <div>
      {count}
      <button type="button" onClick={increment}>
        ADD
      </button>
    </div>
  );
});

function App() {
  return (
    <CounterStore.Provider>
      <Counter />
    </CounterStore.Provider>
  );
}

自动优化

heo 实现了自动按需优化,只有真正用到的数据变化后才会触发 rerender,减少了类似 reduxuseSelector 的模板代码。

由于使用了 Proxy,需兼容低版本浏览器请使用 v1 版本。

API

createStore(useHook)

import { useState, useCallback } from 'react';
import { createStore } from 'heo';

function useCustomHook() {
  const [value, setValue] = useState();
  const onChange = useCallback((e) => setValue(e.currentTarget.value), []);
  return {
    value,
    onChange,
  };
}

const Store = createStore(useCustomHook);
// Store === { Provider, usePicker }

Store.usePicker()

自动监听从 store 中选择出来的值,若值发生改变,则触发 rerender

function ChildComponent() {
  const { value } = Store.usePicker();
  return <span>{value}</span>;
}

<Store.Provider>

Store.Provider 基本用法

function Parent() {
  return (
    <Store.Provider>
      <ChildComponent />
    </Store.Provider>
  );
}

<Container.Provider initialState>

function useCustomHook(initialState = '') {
  const [value, setValue] = useState(initialState);
  // ...
}

function ParentComponent() {
  return (
    <Store.Provider initialState="value">
      <ChildComponent />
    </Store.Provider>
  );
}

Store.useSelector()

通过函数监听当前容器中选择后的值,若值发生改变,则触发 rerender

function ChildComponent() {
  const value = Store.useSelector((state) => state.value);
  return <span>{value}</span>;
}

性能提示

你可能会需要用 useCallback 记住一个回调,但由于内部函数必须经常重新创建,记忆效果不佳,导致子组件重复 rerender。对于复杂的子组件,重新渲染会对性能造成影响。通过 useMethods,可以保证函数地址永远不会变化。

Heo 的灵感来自于 unstated-next,并解决了 unstated-next 中导致的 context 穿透的性能问题,无需过量拆分 Provider 组合来优化组件。 在大型模块/项目中性能极其重要,它能为我们节省大量的调优时间。

License

MIT © MinJieLiu