Hydux: 一个 Elm-like 的 全功能的 Redux 替代品 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
yzhen123
V2EX    程序员

Hydux: 一个 Elm-like 的 全功能的 Redux 替代品

  •  
  •   yzhen123 2017-12-09 18:08:36 +08:00 3065 次点击
    这是一个创建于 2871 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在学习和使用 Fable + Elmish 一段时间之后,对 Elm 架构有了更具体的了解, 和预料中的一样,Elm 风格的框架果然还是和强类型的 Meta Language 语言更搭,只有一个字: 爽。 但是呢,Fable 毕竟是一个小众语言,使用的 F# 语法而且还是来自“万恶”的微软,开发环境还需要依赖 dotnet, 就这几点恐怕在公司的一些正式项目中推行就有些难度。

    刚好最近需要做一个答题小游戏的应用,不想再上 React + Redux 全家桶了,一是体积太大,二是无论配置还是写起来都太繁琐。忽然发现 hyperapp 让我眼前一亮,简洁的架构,elm 风格,1kb 的体积,丰富的生态,简直小应用神器! 但是呢,在实际使用中就发现,hyperapp 破坏性更新太多,导致很多第三方库,比如 persist, Redux Devtools, hmr 都不能用了,虽然这些库实现都不复杂,但是一个个改太麻烦了,又不想用老版本,干脆自己重新造了个轮子 -- Hydux.

    Hydux 的语法和 hyperapp 差不多,抽离了 view 层,支持任意的 vdom 库,包括 react, 特点是 内置了 热更新,logger, Redux Devtools 和 persist,依然是 1kb 大小 (gzip, 不包括开发环境),完全无痛的开发环境,真正的一站式解决方案!

    <img src="

    view 层内置了 1kb 的 picodom, 同时也有官方支持的 React 扩展 使用 React 来渲染.

    说了这么多,还是上点代码: 首先我们有一个 counter 模块,代码和 Elm 的组织方式很类似,不需要像 Redux 在 Actions/Reducers/ActionTypes 中跳来跳去的

    // Counter.js export default { init: () => ({ count: 1 }), // 初始化状态 actions: { // actions 改变状态 down: () => state => ({ count: state.count - 1 }), up: () => state => ({ count: state.count + 1 }) }, view: (state: State) => (actions: Actions) => // view <div> <h1>{state.count}</h1> <button Onclick={actions.down}></button> <button Onclick={actions.up}>+</button> </div> } 

    然后呢,我们可以像 Elm 一样 复用 模块, 以前在用 Redux 时总是会面临不知道怎么复用才好的问题,而实际上 Elm 的复用是超级简单和方便的。

    import _app from 'hydux' import withPersist from 'hydux/lib/enhancers/persist' import withPicodom, { h, React } from 'hydux/lib/enhancers/picodom-render' import Counter from './counter' // let app = withPersist<State, Actions>({ // key: 'my-counter-app/v1' // })(_app) // use built-in 1kb picodom to render the view. let app = withPicodom()(_app) if (process.env.NODE_ENV === 'development') { // built-in dev tools, without pain. const devTools = require('hydux/lib/enhancers/devtools').default const logger = require('hydux/lib/enhancers/logger').default const hmr = require('hydux/lib/enhancers/hmr').default app = logger()(app) // 内置的 logger app = devTools()(app) // 内置的 Redux Devtools 扩展支持 app = hmr()(app) // 内置的热更新模块 } const actiOns= { counter1: Counter.actions, counter2: Counter.actions, } const state = { counter1: Counter.init(), counter2: Counter.init(), } const view = (state: State) => (actions: Actions) => <main> <h1>Counter1:</h1> {Counter.view(state.counter1)(actions.counter1)} <h1>Counter2:</h1> {Counter.view(state.counter2)(actions.counter2)} </main> export default app({ init: () => state, actions, view, }) 

    然后就可以了!简单,可控,无痛的开发环境和代码组织。

    在线 demo

    异步使用的是类似 Elm 的副作用管理器风格, actions 可以是完全纯的函数,也可以是直接返回一个 promise: https://github.com/hydux/hydux#actions-with-cmd

    官网: https://github.com/hydux/hydux

    官方支持的 React 扩展: https://github.com/hydux/hydux-react

    4 条回复    2017-12-09 21:55:35 +08:00
    feichao
        1
    feichao  
       2017-12-09 18:33:56 +08:00
    看起来不错的样子
    bramblex
        2
    bramblex  
       2017-12-09 19:21:36 +08:00
    虽然我始终觉得在 JS 里面折腾纯函数式就是闲着蛋疼……

    但还是支持一波
    yzhen123
        3
    yzhen123  
    OP
       2017-12-09 20:43:40 +08:00
    @bramblex 同意,其实我业余项目一般是用 Fable/Elmish, 函数式强类型不严格区分副作用的语言(ML 语言)写起来才是最舒服的,但是很多时候还是不得不写 js, 比如公司项目。而找了半天觉得 hyperapp 的风格算是在 js 中最接近 Elm 的了,但是坑有点多,就造了个轮子,扩展了一下,配合 ts 应该可以勉强找回一点 Elm 的感觉吧
    bramblex
        4
    bramblex  
       2017-12-09 21:55:35 +08:00 via iPhone   1
    @yzhen123

    嗯,我以前折腾 purescript,用 effct 处理副作用还是挺舒服的。虽然公司项目我肯定不敢这么浪
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2737 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 13:58 PVG 21:58 LAX 06:58 JFK 09:58
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86