React开发者转投Hyperapp:6大概念映射与心智模型迁移完全指南
【免费下载链接】hyperapp1kB-ish JavaScript framework for building hypertext applications项目地址: https://gitcode.com/gh_mirrors/hy/hyperapp
对于 React 开发者来说,学习 Hyperapp 的最大误区是"又要重新学一套框架"。其实Hyperapp是一个 1kB 左右的超轻量 JavaScript 框架,仅靠h()、text()、app()三个函数就能构建完整的 Web 应用。好消息是:它在数据流、单向更新、纯函数渲染这些底层心智上,与 React(尤其是 Redux 时代的 React)高度同构,你只需要把 6 个核心概念对号入座,一天之内就能上手写生产级应用。
一图看懂:React 与 Hyperapp 概念对照总表
| # | 你的 React 记忆 | Hyperapp 对应概念 | 一句话解释 |
|---|---|---|---|
| 1 | useState/ Reduxstore | State(统一状态) | 全局一份init,没有组件私有状态 |
| 2 | JSX + 组件树 | View(h()+text()) | 纯函数返回虚拟 DOM 节点 |
| 3 | 事件回调 / reducer | Action(动作) | 纯函数,接收状态、返回新状态 |
| 4 | useEffect(对外) | Effect(效果) | 副作用出口:发请求、写存储 |
| 5 | useEffect+ cleanup(对内) | Subscription(订阅) | 副作用入口:键盘、定时器、轮询 |
| 6 | Redux middleware | Dispatch(调度) | 可插拔的 dispatch 管道,支持调试 |
这张表就是全文的路线图,下面逐个拆解。
映射1:从 useState 本地状态到全局统一 State
React 里状态是"分散"的:每个组件一个useState,跨组件共享靠 props 或 Context。Hyperapp 反其道而行——整个应用只有一份状态,由app()的init:初始化,视图、动作、订阅共享访问同一份数据。
app({ init: { todos: [], value: "" }, view: ({ todos, value }) => h("main", {}, [/* ... */]), node: document.getElementById("app"), })心智迁移要点:
- 忘掉"组件状态",拥抱"应用状态的切片"。子组件想要什么数据,从全局状态里解构即可。
- 状态变更永远不可变:必须返回新对象(
{ ...state, x: 1 })。直接 mutate 原状态,Hyperapp 检测不到变化,页面不会更新——这与 Redux 的纪律完全一致。 - 状态越扁平越好,官方建议状态可序列化,方便持久化与调试。
📌 详见 docs/architecture/state.md
映射2:从 JSX 到 h() 与 text() 虚拟 DOM
React 用 JSX 语法糖描述 UI;Hyperapp 没有 JSX,直接用h()创建元素节点、text()创建文本节点,组合出虚拟 DOM 树:
h("input", { type: "text", oninput: NewValue, value }), h("button", { onclick: AddTodo }, text("New!")),规则非常简洁:
h(tag, props, children)对应 JSX 标签,children必须是数组。- 类名
class既可以是字符串,也可以是对象(值 truthy 才生效),条件类名写法与 React 的classnames习惯如出一辙。 - 列表渲染同样需要
key,让 diff 算法精准复用节点。 - 视图是纯函数:
(state) => VNode,不持有任何状态,与 React 的 stateless 组件同构。
Hyperapp 的 diff 算法高度优化,源码不足 400 行,想理解细节可直接阅读核心文件 index.js;类型签名参考 index.d.ts。
📌 详见 docs/architecture/views.md
映射3:从事件回调到 Action——Hyperapp 的灵魂
这是 React 开发者感受最强烈的差异。React 的事件回调里可以干任何事(setState、发请求、改 DOM);而 Hyperapp 把"改状态"和"产生副作用"彻底分开:
Action = 无副作用的纯函数:
(state, payload) => newState
const AddTodo = (state) => ({ ...state, todos: state.todos.concat(state.value), })把 Action 挂到事件属性上(onclick: AddTodo),点击时框架自动分发它。Action 还可以:
- 携带 payload:
onclick: [AddBy, 5] - 返回另一个 Action(动作链式包装,优雅地预处理事件对象)
- 返回
undefined来停止整个应用(自动清理全部订阅与事件)
如果你写过 Redux,这就是 reducer;如果只写过useState,这里就是最需要刻意练习的一点:事件处理器里不许写副作用,副作用要"申请"给框架执行。
📌 详见 docs/architecture/actions.md
映射4:useEffect 一分为二——Effects 与 Subscriptions
React 的useEffect身兼两职(对外发请求 + 对内监听事件),这也是它心智负担重的根源。Hyperapp 把它拆成两个方向,职责清晰:
Effect(效果)——应用向外:Action 返回[newState, ...effects],框架负责执行这些副作用。效果器(effecter)能拿到dispatch,异步完成后"回派"结果:
const Select = (state, selected) => [ { ...state, selected }, jsonFetcher(url, GotBio), // fetch 完成后再 dispatch GotBio ]Subscription(订阅)——世界向内:键盘、窗口尺寸、定时器、地理位置等全局事件,通过subscriptions: state => [...]声明式绑定,并可随状态条件启停(条件为 falsy 时自动清理,等价于useEffect的 cleanup)。
subscriptions: (state) => [ state.selected !== null && onKeyDown("ArrowUp", SelectUp), ]官方配套包把常用订阅做得开箱即用:packages/time/(间隔与时间)、packages/events/(鼠标、键盘、窗口事件),还有 packages/dom/、packages/svg/、packages/html/ 等。
📌 详见 docs/architecture/effects.md 与 docs/architecture/subscriptions.md
映射5:从组件到 View Component——更简单的组合
React 组件有生命周期、有 hooks、有 memo 体系;Hyperapp 的"组件"就是普通函数,接收 props 返回 VNode,没有任何特殊机制,纯靠函数组合:
const person = (props) => h("div", { class: "person" }, [ h("p", {}, text(props.name)), ])- 组件不拥有状态(状态在全局),因此天然没有"prop drilling 到 useState"的别扭。
- 需要性能优化时用
memo()惰性渲染,等价于React.memo的思路:props 没变就不重算。 - 命名建议:组件用驼峰名词(
articleHeader),Action 用帕斯卡动词短语(AddTodo),Effect/Subscription 用驼峰动词(onKey),命名即文档。
📌 详见 docs/api/memo.md
映射6:从 Redux middleware 到 Dispatch 管道
app()返回的dispatch就是应用唯一的数据入口。Hyperapp 允许你注入dispatch 初始化器,像中间件一样包裹默认 dispatch——调试日志、状态快照、不可变代理保护都能实现:
app({ /* ... */ dispatch: logActionsMiddleware, // 每次分发自动打印动作名 })这正好接住了 Redux 用户"我想要 middleware 做埋点/调试"的需求,而且实现极其轻:dispatch 本身就是可递归、可组合的函数。
📌 详见 docs/architecture/dispatch.md
迁移必看的3个坑与学习路径
坑1:直接 mutate 状态。state.count++后返回同一个引用,Hyperapp 认为状态没变,界面纹丝不动。永远返回新对象。
坑2:在 Action 里写副作用。Action 必须纯。发请求?返回[newState, someEffect];监听全局事件?放进subscriptions。纯度是整套架构可靠性的来源。
坑3:忘记列表 key。数组渲染的 VNode 不带key,diff 只能假设全部变化,性能与状态都会出问题。
推荐学习路径(由浅入深,全程无需构建工具):
- 快速上手:docs/tutorial.md —— 从 Hello World 到订阅,一步步搭出完整应用
- 概念速查:docs/reference.md —— API 与架构术语总表
- 深入架构:docs/architecture/flowchart.md —— 一张流程图看懂 State→View→Action→Effect 的完整循环
- 真实项目:packages/ 目录下每个官方包都是最小可用的完整示例
结论:React 开发者迁移 Hyperapp,本质是从"组件为中心"切换到"状态为中心"的单向数据流。概念少到一屏能数完,心智负担显著下降,而函数式纯度让你对"状态为什么变了"永远有答案。1kB 的体量 + 几乎为零的学习成本,使它成为理解前端框架原理的最佳教具,也是构建轻量应用的务实选择。
【免费下载链接】hyperapp1kB-ish JavaScript framework for building hypertext applications项目地址: https://gitcode.com/gh_mirrors/hy/hyperapp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考