【Redux】基于Typescript的精简版Redux实现

这里写图片描述

前言

在学习Redux之前,我希望做出一个精简版的redux。这能帮助我们更好地理解redux。

为什么我们需要redux

Redux 的创造者 Dan Abramov 说过:“只有遇到react解决不了的问题,你才需要redux”。
因此,redux不是必须,我们需要知道,什么时候我们才需要redux,像一些业务逻辑简单的应用,状态不会多到难以管理,那我们就不需要redux,相反,这种情况下引入redux会使你的应用变的难看,难以阅读。
redux的作用就在于它能集中的管理状态,让我们更能以数据驱动的方式思考应用构建,因此,很多时候,redux还是很有必要的。

redux有几个重要的概念,Store,Action,Reducer,这里不在赘述,我们马上就会讲到它,接下来我们试着实现一个基于typescript精简版的redux。

实现一个精简版的redux

在实现之前,我们需要简单的说明一下redux的三个核心。
Store
store能集中的管理状态,它好似一个状态的数据库,但是每个状态都是只读的,如果你需要修改它,你必须创建一个描述,让Reducer来修改它
Action
action就是一个描述,它默认带有两个字段,type和payload,type是必须的,payload却不是必须的,type描述需要怎样修改,payload翻译过来是有效载荷,在程序设计中,可以把payload理解为有效数据。
Reducer
reducer是可以用来改变state的一个对象,它接收一个state和一个action作为参数,action描述怎样去更新state,redux并不赞成直接修改state,所以reducer会作为一个pure function 存在。

Start

在开始之前,我们确定我们的这个demo是实现一个简单的计数器。
首先我们必须明确state是什么类型。
创建一个state来对它进行约束,明确的指出state带有一个count的属性

interface AppState{
    count:number;
}

接下来我们创建一个用于描述的Action,
拥有一个type属性用于描述更新类型,
payload作为可选属性,类型可以是任意类型

interface Action{
  type:string,
  payload?:any
}

创建完了Action和state,接下来我们可以试着写一个reducer

interface Reducer<T>{
  (state:T,action:Action):T
}

创建一个具体的reducer

let reducer:Reducer = (state:AppState,action:Action) => {
  switch(action.type){
    case "INCREMENT":
        return Object.assign({},state,{count:state.count + 1} as AppState);
    case "DECREMENT"
        return Object.assign({},state,{count:state.count - 1} as AppState);
    default:
        return state;
  }
}

reducer内部用了一个switch语句,用于进行多态分发,值得注意的是,reducer是一个pure function,它不试图改变state的值,而是用Object.assign进行合并返回一个新的对象,这符合函数式编程,这样做的一个大好处是我们可以很简单的实现撤销/恢复,不会改变状态的值,因此可以避免很多莫名其妙的错误。

store
store的创建,让我们可以保存自己的状态,对状态进行集中的管理,下面就来写一个具体的store

class Store<T>{
  private state:T;

  constructor(private reducer:Reducer, state:T){
    this.state = state;
  }

  dispatch(action:Action){
    this.state = this.reducer(this.state,action);
  }

  getState():T{
    return this.state;
  }
}

到现在为止,我们已经创建出了一个精简版的redux,我们进行尝试

//创建store
let store:Store<AppState> = new Store(reducer,{count:0} as AppState);

store.dispatch({type:"INCREMENT"} as Action);
console.log(store.getState()); //1

我们可以发现已经成功了。但是我们发现这并不能为我们带来许多的便利,很大的一个原因是我们整个demo的目的是要做出一个计时器,整个应用也只有一个状态需要管理,如果这是一个真实的例子,那么我们这样无疑是小题大做。

另一方面,我们希望在dispatch进行分发过后马上通知自己,而不用再去打印getState的值。我们可以添加一些监听者。

没有多麻烦,我们只需要修改一下store即可,在此之前,我们需要一个listener

它形如

它只是一个普通的无参函数,没有什么可讨论的

interface Listener{
  ():void;
}

现在再来修改store

class Store<T>{
  private state:T;
  //存储listener的容器
  private listeners:Array<Listener> = [];

  constructor(private reducer:Reducer, state:T){
    this.state = state;
  }

  dispatch(action:Action){
    this.state = this.reducer(this.state,action);
    //分发过后遍历整个监听器容器并执行
    this.listeners.forEach(l => l());
  }

  getState():T{
    return this.state;
  }

  //订阅
  subscribe(listener:Listener){
    this.listeners.push(listener);
    return () => {
      this.listeners = this.listeners.filter(l => l !== listener);
    }
  }
}

现在再试试看?

//创建store
let store:Store<AppState> = new Store(reducer,{count:0} as AppState);
let unsubscribe = store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch({type:"INCREMENT"} as Action); //1
store.dispatch({type:"INCREMENT"} as Action); //2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值