flooks v4,自动优化,按需更新。最简单 React Hooks 状态管理器

2021-07-28 12:54:13 +08:00
 nanxiaobei

状态管理的难题

在 React Hooks 状态管理方案中,通常会遇到联动更新的问题:

同一模块更新,消费了此模块的组件都会 re-render,即使被更新的 state 在组件中未用到。

例如 model = { a: 1, b: 2, fn: () => {} },调用 setModel({ a: 2 }),只使用 b 的组件也会 re-render 。而只使用 fn 函数的组件,理论上永远不应被 setModel() 触发更新,但也会 re-render 。

若不想被关联更新,就得将数据拆的足够细 —— 例如 React.useState() jotai 等,便是这种 "元数据" 思路。而同时还存在另一种 "模块化" 思路,例如 React.useReducer(),希望将同一模块的数据放在一起。

使用 "元数据",会背离将数据放在同一 model 的初衷,使用 "模块化",又面临着组件联动更新的问题。

使用 Redux 的传统 class 组件项目中,react-redux 实现了对组件联动更新的性能优化。但纯粹的 React Hooks 项目,只使用 Hooks 实现的状态管理器,却没有一个好的解决方案。

flooks v4 介绍

flooks 是一个专用于 React Hooks 的状态管理器,API 极其简单。即支持模块化,又支持模块间的互通,可能是最简单的一个。

https://github.com/nanxiaobei/flooks

之前 flooks v3 的 API 是这样的:

const counter = (now) => ({
  count: 0,
  add() {
    const { count } = now();
    now({ count: count + 1 });
  },
});

function Counter() {
  const { count, add } = useModel(counter, ['count']); // 借助 deps 知晓注入的 state
  return <div />;
}

flooks v4 做了一些更新:

const counter = ({ get, set }) => ({
  count: 0,
  add() {
    const { count } = get(); // get
    set({ count: count + 1 }); // set
  },
});

function Counter() {
  const { count, add } = useModel(counter); // 再不需要 deps
  return <div />;
}

主要改变是:

除了 API 更新,更重要的是,flooks v4 将背后的更新核心逻辑进行了全部重写,彻底解决了 "模块化" 方案联动更新的问题,从而实现了对更新颗粒度的精细控制。

Re-render 自动优化方案

借助 proxy,flooks 实现了惊人的自动优化,完全按需 re-render,React 真正变为 "react"。

useModel(someModel) 返回一个 proxy,只有真正用到的数据,才会注入组件,若未用到,则不会注入。

因此无需再添加 deps,因为 useModel() 现在已经可以知道,哪些数据会被解构出来使用,从而只更新用到的数据。

只使用函数绝不触发 re-render

const { fn1, fn2 } = useModel(someModel); // A 组件

const { b, setB } = useModel(someModel); // B 组件
setB(); // A 无 re-render

若 A 中只使用函数,则其它组件更新不触发 A re-render 。

未使用的 state 绝不触发 re-render

const { a } = useModel(someModel); // A 组件

const { b, setB } = useModel(someModel); // B 组件
setB(); // A 无 re-render

若 A 中未使用某些 state,则其它组件更新不触发 A re-render 。

未使用的 loading 绝不触发 re-render

const { someFn } = useModel(someModel); // A 组件
someFn(); // 无 someFn.loading,无额外 re-render

若 A 中未使用 someFn.loadingsomeFn() 不触发额外 re-render 。

someFn 为异步,普通 loading 方案中,即使 somefn.loading 未用到,re-render 也会触发至少两次(先 true 然后 false)。但使用 flooks,若 somefn.loading 未用到,则完全不会存在隐形 loading 更新。

真正的 "模块化"

以上,flooks v4 真正实现了 React Hooks 状态管理方案的 "模块化"。

即可以将同一模块的数据放在一处,方便统一管理,又不用担心局部更新触发联动更新。更新完全是按需进行,只有用到的数据,才触发更新,未用到的数据,即使是 someFn.loading,也不会注入组件。

在代码中写出来的,就是会更新的,没有写的,就根本不会存在,再不用担心更新问题。

一切都是如此符合直觉,再无其它烦人概念。

结束啦

flooks v4,喜欢的话,欢迎 ✰

https://github.com/nanxiaobei/flooks

1889 次点击
所在节点    React
6 条回复
qfdk
2021-07-28 13:01:48 +08:00
感觉好像很不错 等假期回来
powerfulyang
2021-07-28 14:51:09 +08:00
@umijs/plugin-model 这两个看起来好像
nanxiaobei
2021-07-28 15:29:15 +08:00
@qfdk #1 😂
nanxiaobei
2021-07-28 15:29:46 +08:00
@powerfulyang #2 完全不一样,只是名字里都带 "model","model" 这个名词是 rematch 发扬光大的
statumer
2021-07-30 02:13:15 +08:00
感觉楼主的这个 loading 功能不错
nanxiaobei
2021-07-30 11:53:00 +08:00
@statumer #5 😊

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/792253

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX