V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
masahiro
V2EX  ›  前端开发

smox 2.0 强势发布!状态管理最佳设计

  •  
  •   masahiro ·
    132yse · 2019-01-07 14:10:33 +08:00 · 2730 次点击
    这是一个创建于 2134 天前的主题,其中的信息可能已经有所发展或是发生改变。

    唔,大家好呀,我是 132,那个,我又来了::>_<::

    smox 是我去年这个时候写的 react 状态管理库,从最初的 redux 替代品,到 react 版本的 vuex,一直在进步

    直到前阵子,突然来了新的灵感,这次 smox 2.0,不再仅仅是进步品这么简单,内部实现除了还保留发布订阅机制,其他的实现已经不一样了。

    可以这么理解,redux 是 flux、elm 的进步实现,smox 却是 redux 的进步实现

    废话不多说,上 API

    Use

    const state = {
      count: 2
    }
    
    const actions = {
      up(state, data) {
        state.count += data
      },
      down(state, data) {
        state.count -= data
      }
    }
    
    const effects = {
      async upAsync(actions, data) {
        await new Promise(t => setTimeout(t, 1000))
        actions.up(data)
      }
    }
    
    const store = new Store({ state, actions, effects })
    

    如你所见,actions 和 effects 都是对象,里面存放的是函数,参数为他们要触发的对象

    看似没什么不一样的地方,但是同样的 API 实现,我却冥思了一天

    Nexted

    这里面最重要的是 path 机制,我称之为 nexted-proxy

    actions 和 effects 接受的参数,是被限制作用域的,什么意思?

    const state = {
      counter:{
        count: 2
      }
    }
    
    const actions = {
      counter: {
        up(state, data) {
          state.count += data
        },
        down(state, data) {
          state.count -= data
        }
      }
    }
    
    @map({
      state:['counter/count'],
      actions:['counter/up','counter/down']
    })
    

    也就是说,可以通过包裹对象的形式,进行 store 拆分,smox 会自动将 key 作为 path 不断往下传递,上面的例子中,actions 接收的 state 就是 counter 对象下的 state

    这个机制是 smox 最成功的一个机制了,对比 rematch、dva 的 model 机制更灵活强大,设计上也更精彩√

    Proxy

    immed 是我写的一个小库,可以理解为 immer 的迷你实现

    它的作用和 immer 一样,可以将对象 copy 一份,来保证不可变

    同时,使用 Object.defineproperty 对 IE 进行兼容,我好贴心::>_<::

    架构和 API 设计

    在 smox 中,actions 的方法能够不去 return,是 immed 的功劳,不去 return 会让这个 API 变得好看太多了

    至于 effects,它其实一层副作用的包裹,通常用来异步执行 action

    通过 async/await,也可以不去回调了( then 方法除外),这样以来,这个 API 也变得完美了

    如此,smox 的架构变得非常清晰:

    state <- actions <- effects 形成闭环,完美的架构设计

    以上,再无其他。

    可能你会问,dispatch 去哪儿了? reducer 去哪儿了? action.type 去哪儿了?

    当然是没了。

    redux 设计 dispatch 是为了保证 action 触发的唯一性,也就是 action 必须由 dispatch 触发,最终保证的是 state 只由 action 而改变

    smox 不需要 dispatch 也可以做到,因为 smox 的 actions 是封装过函数,state 最终同样可以保证 state 只通过 action 改变

    所以,对比 redux,smox 的设计中,移除了 dispatch,reducer 这种概念

    同样的作为进步品的 rematch、dva 等,是没有变化的,也就是没有改变 redux 的本质

    smox-react

    看完了 smox,再来看 smox-react

    @map({
      state: ['count'],
      actions: ['up', 'down'],
      effects: ['upAsync']
    })
    class Counter extends React.Component {
      render() {
        return (
          <div>
            <div>{this.props.count}</div>
            <div>{this.props.sex}</div>
            <button onClick={() => this.props.up(1)}>+</button>
            <button onClick={() => this.props.down(1)}>-</button>
            <button onClick={() => this.props.upAsync(1)}>异步</button>
          </div>
        )
      }
    }
    

    如上,最重要的是 map 这个 API,大家可还曾记得 connect ?

    我随便从网上找了个 dva 的 connect 长这样:

    @connect(({ user, login, global = {}, loading }) => ({
      currentUser: user.currentUser,
      collapsed: global.collapsed,
      fetchingNotices: loading.effects['global/fetchNotices'],
      notices: global.notices,
      menuData: login.menuData,
      redirectData: login.redirectData
    }))
    

    这可能是我……学习 react 见过的最可怕的 API 没有之一了::>_<::

    没有对比就没有伤害,smox 的 map 其实抄自 vuex 的 mapXxx,以字符串数组的形式去遍历,然后筛选出对应的 state 和 函数,注入到组件中

    这个 API 我也封装到极致了可以说::>_<::

    smox-react 还有一处比较讨喜,就是,不再需要 bindActionCreators,毕竟已经不再需要 dispatch 了嘛

    总结

    smox 2.0 是我年前最棒的一次重构了,标题写个最佳应该不过分,至今没有发现能把 API 封装到 smox 这个程度的√

    对比同为进步品的 rematch、dva 等,除了 API 更加好看,还放弃了 redux 原有的机制,是创造,不是封装√

    这一切的一切,仅仅只有 1kb

    最后,放上 smox 的 github 地址:

    https://github.com/132yse/smox

    欢迎试用与 star !

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2549 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:48 · PVG 23:48 · LAX 07:48 · JFK 10:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.