我厌倦了Redux,那就造个轮子:Rectx

#1

前言

Redux 的究极状态形态基本就是 DVA,也就是封装自 Redux + Redux-saga。不过,我并没有使用 DVA ,因为项目较早。我自己也有自己的封装,只不过一开始的时候,并没有 DVA 那么完整的概念,后来参考 DVA 以后,我重新写了个 mini 库,代码大约 120 行左右,已经在公司内部全面使用。

这个库实现了 page (页面)和 model 的自动加载,省去了一个一个 import modelimport page 的痛苦,具体的,可以阅读代码和 Readme .

不过,本文并不是讲述如何构建一个类 DVA 状态管理库,我说过,我厌倦了 Redux

分析与思考

在我们刚刚学习 React 的时候,很快就能接受了 状态机组件化 的思想,并且很快能够写出一个 React 程序。

import React from 'react'

class App extends React.component{
   state={
     count:0
   }
   handleClick = ()=>{
      this.setState({
        count:this.state.count + 1
      })
   }

   render(){
     return (<div onClick={this.handleClick}>
             {this.state.count}
           </div>)
   }
}

我们将一个一个组件进行封装,每个组件都有自己的状态,相互不污染,相互不限制,这看似是一件美好的事情。

但是,当我们哪怕是做一个 TODOLIST 就会发现,我们必须要进行 状态共享。状态共享对于React 来说是一个大难题,为了解决这个问题,人们从开始的 Flux 架构,一直到现在广为流传的 Redux / Mobx 架构。

但是,我认为这无疑是给 React 增加了很多概念。我知道我知道,你 或许一定肯定必须是 一个 Redux 究极粉丝,但是认真想一下,状态共享真的需要引入这么多概念吗?

最大痛点:概念过多、学习陡峭

这一直是 Redux 的一个毛病,我们就来看看要完整的使用 Redux 我们必须要掌握一些什么东西:

  • 理解 Redux 全局状态机的机制,actionreducerselector等概念
  • 巨大状态机的拆分,使用 combindReducer( ) 函数
  • 需要掌握一些中间件,目前最佳的是 redux-saga
  • 使用 react-redux 库,书写 mapStateToProps 等函数
  • 想要书写一个完美的 react-redux 应用,上述的四点,已经成为现在的一个指标。虽然类似如 DVA 等库已经帮我们进一步的封装,屏蔽了上述的一些细节,但是我们的学习成本依旧不低。

轻量化状态管理

作者 Dan 其实已经意识到了这一点,并且在最近的 React 版本中构建了一套全新的 Context API,想通过这一套机制,逐步的代替 Redux

今天,我就来给大家介绍一种轻量级的状态管理方式,为什么我说是轻量级?

  • 使用最初版本的 setState() 去更新我们的 全局状态
  • 使用 class 的方式,对 全局状态 进行切分,而不是引入类似 model 等方式
    因为原本就是 setState,因此我们无需引入任何中间件就可以处理副作用。
    那么,就让我们引入我最近在研(抄)究(袭)的轮子:215566435/rectx

Controller 类

等等,controller 是什么鬼?这是在写后台么!?放心,不是,只是一个简单的概念而已。

Controller 用于存放一堆逻辑相关的状态与更新状态的逻辑等等,以 class 形式组织
我们直接来看代码:

import { Controller } from 'rectx'

class LikeController extends Controller {
    state = {
        isLike: false,
        isMount: false
    }

    handleClick = () => {
        this.setState({
            isLike: !this.state.isLike
        })
    }
}

非常简单的几步,就完成了一个 Controller 的书写

  • State:用于存放初始状态
  • this.setState:你没看错,这里的 this.setStateReactthis.setState 是一样的,作用就是更新状态

Listen 组件

Listen 组件是一个抽象组件,封装自 context.comsumer,用于传递 Controller 的状态,方法等。

const Like = () => (
    <Listen
        to={[LikeController]}
        didMount={like => {
            like.setState({ isMount: true })
        }}
    >
        {like => (
            <div>
                <button 
                  onClick={() => like.handleClick()}
                >
                  Click me
                </button>
                <div>
                {like.state.isMount ? 
                 'component being loaded' : 
                'component not loaded'}
                </div>
                <div>
                {like.state.isLike ? 
                'I love you' : 
                'I hate you'}
                </div>
            </div>
        )}
    </Listen>
)
  • 这是一个叫做 Like 的 无状态组件
  • Listen 组件有一个 propstoto接收一个或者多个 controller ,并以render props的形式渲染子组件
  • render props 函数的参数,就是我们刚刚输入进 Listen 组件的实例
  • Listen 组件还有一个 didMount 函数,用于监听被订阅组件的挂载是否成功

是不是开始明白了?Listen 组件能够依赖注入式的将我们的 Controller 输入到组件之中,然后我们的组件就可以很好的使用我们的 Controller 中的方法、状态,并且,每个 Controller 提供的状态是完全隔离的!

Provider 组件

react-reduxprovider 组件类似,但是无需输入参数

render(
  <Provider>
    <Like />
  </Provider>,
  document.getElementById("root")
);

好了,这样就已经完成了!如果你想要看真实的效果,请去:l970jx93pz - CodeSandbox

是不是非常的简单?回头看一下我们的状态管理

我们引入了一个 Controller 的概念,对我们的状态进行管理。这样的好处在于:

  • 现在,我们将全局的 store 拆分成了一个一个的类,这些类可以放在不同的文件中,形成天然的模块化,我们还可以对这些类进行统一的封装,管理完全的面向对象化
  • 我们将 state 聚合在一个类中,更新类的方式使用为原本 ReactsetState,使得开发人员只要掌握了 React,那么只需要再掌握 Rectx 的几个「React 组件的用法」,就可以完成对状态的管理
  • 无需中间件就可以完成对副作用的控制:嘿~因为我们使用的是 setState~

当然,我认为,Rectx 还需要进一步的封装才能更加好用,我也将使用 rectx 重写我的一些应用。

仓库地址:rectx

喜欢的给点星星哦

1 Like