V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
yzhen123
V2EX  ›  程序员

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

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

    在学习和使用 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   ·   实用小工具   ·   2781 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 554ms · UTC 08:47 · PVG 16:47 · LAX 00:47 · JFK 03:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.