资讯专栏INFORMATION COLUMN

Redux入门0x101: 简介及`redux`简单实现

ssshooter / 2260人阅读

摘要:在我看来它们的关系不会比共用开头更深了,所以我就重新开了一个头,但其实是基于前面写的资源中文文档英文文档官方视频学习历程当初为了学习,看了许多的材料,中途曾经放弃两次,但是最后还是勇敢的拿起了它,现在终于勉强弄懂。

0x000 概述

这一章开始讲redux,其实是承接前面的react,但其实作为一个框架来说,reduxreact并没有太多的关系,本身是独立存在的。在我看来它们的关系不会比共用re开头更深了,所以我就重新开了一个头,但其实是基于前面写的...

0x001 redux资源

中文文档

英文文档

官方视频

0x002 学习历程

当初为了学习redux,看了许多的材料,中途曾经放弃两次,但是最后还是勇敢的拿起了它,现在终于勉强弄懂。

第一次是大家都说redux牛逼,所以就打算学习一下,看了许多遍了redux中文文档,也看了英文文档--因为有些demo总是跑的不成功,怕是中文更新不及时的原因。但最后还是不了了之,因为不知道用它来干啥,反倒弄出了一堆的reduceraction之类的东西。

第二次是在做毕业设计的时候,做了一个类似看板一样的api自动测试及性能统计分析项目--类似postman,在这里遇到了一些超级棘手的问题,其中的最大的问题就是组件间通信统一的状态管理。因为是有一个超级复杂的组件操作方式和组件嵌套,在做组件间通信的时候,为了保持状态的一致性,不断的将事件和属性一层一层往下传、或者往上传。真是糟糕的回忆啊....... 当时用的是Angular2。而我为了解决这个问题,写了一套基于订阅-发布模式的事件通知框架,原本想解决这些问题,结果,确实解决了组件间通讯统一状态管理的问题,但是最终带来的确实更加复杂的事件管理和更加无无序的组件关系....

后来使用vue+vuex做了一些项目,反倒是突然领悟的redux的思想,就开始了第三次的学习,直到现在,我觉稍微缓解了我在前端项目所受到的伤害,redux的文档有点像上帝视角,他好像在说,我知道你应该知道的,所以我这么说你应该懂得,其实我不懂。所以我要从凡人视角说说redux扒开他的神袍,看看他的胸毛......

0x003 再说一些废话

在前面react的文章中,我一直在重复react中都是js,就是为了把思想引回react的本质,react是基于js写的一个框架而已,只是一个框架,并不是一门独立的语言。很多人总是用了jQuery就忘了原生,用了React就忘了jQuery和原生。而来了redux,就必须和react绑定。这是一个极大的思想误区,从个体上来说,vue是独立的、自由的,react也是独立的、自由的,redux也是独立的、自由的。

的确有redux在react中的最佳实践,却绝对没有redux的唯一实践这种说法,在js的世界中,各大框架各放异彩,他们既可以兼容并济,也可以相互排斥,不过就是js中的一员罢了。每个框架就像每个人一样,有自己的特点,react可以构建uiredux能够管理状态,axios在行网络,angular啥都行!你可以在vue中使用redux,也可以在vue中使用jQuery,甚至也可在你自己的项目中同时使用vuereact,语言也好,框架也罢,都是为了向伟大航线进发而服务的。

一句话总结:自由,然后秩序,接着是世间万物

0x004 订阅-发布模式

redux本质上也是基于订阅-发布模式的产物(我记得没错的话,如果记错了,之后回来改),和我写的那个小框架一样.....,所以在使用redux之前,先来研究一下这个模式,看看我之前写的那个小东西:

let eventMap = {}

class MyEvent {

    /**
     * 发布一个事件并附带一份数据
     *
     * @param name 发布的事件名
     * @param data 附带的数据
     */
    static pub(name, data) {
        if (!eventMap.hasOwnProperty(name)) return
        let callbacks = eventMap[name]
        if (callbacks.length === 0) return
        callbacks.forEach((callback) => {
            callback(data)
        })


    }

    /**
     * 订阅一个事件并附带一个回调
     * 说明这个事件发生的时候所要做的事情
     *
     * @param name 订阅的事件名称
     * @param callback 回调
     * @returns {function(): *} 返回一个函数, 执行这个函数将会取消订阅
     */
    static sub(name, callback) {
        let callbacks = []
        if (eventMap.hasOwnProperty(name)) {
            callbacks = eventMap[name]
        }
        callbacks.push(callback)
        eventMap[name] = callbacks
        return () => callbacks.shift(callback)
    }

}

export default MyEvent

这个库一共只有两个接口:

pub(name:String,data:data):void:发布一个事件,这个事件附带一些数据,当这个事件发布的时候,所有订阅这个事件的都将会收到通知,并执行订阅这个事件的时候定义的操作,即回调函数。

sub(name:String,callback:Function):Fuction:订阅一个事件,当这个事件发生的时候,即调用pub的时候,该callback就会执行,并且在callback中可以收到这个事件发生的时候的附带数据。该函数还返回一个新的函数,调用这个函数可以取消订阅该事件

案例:

import MyEvent from "../../0x012-component-communication/src/MyEvent"

// 定义一个变量
let num = 1
// 定义一个事件名
const EVENT_INCREMENT = "EVENT_INCREMENT"

// 订阅这个事件,并将取消订阅的函数保存起来
let unSub = MyEvent.sub(EVENT_INCREMENT, (data) => {
    console.log(data)
})
// 当 num 发生变化的时候,发布这个时间
num += 1
MyEvent.pub(EVENT_INCREMENT, {num: num})

// 当 num 发生变化的时候,发布这个时间
num += 1
MyEvent.pub(EVENT_INCREMENT, {num: num})

// 取消订阅
unSub()

// 当 num 发生变化的时候,发布这个时间
num += 1
MyEvent.pub(EVENT_INCREMENT, {num: num})
// 当 num 发生变化的时候,发布这个时间
num += 1
MyEvent.pub(EVENT_INCREMENT, {num: num})
console.log({num})

查看浏览器,可以看到,我们收到了两次通知,因为我们在中途取消了订阅

原理就是保存了MyEvent中的eventMap保存了一个Map,该Map是一个String=>Array,当我们订阅事件的时候,即调用sub的时候,就会形成如下的数据结构:

name                 |    callbacks
EVENT_INCRECEMENT    |    (data)=>{...}
-                    |    (data)=>{...}
-                    |    (data)=>{...}
EVENT_DECRECEMENT    |    (data)=>{...}
-                    |    (data)=>{...}

当我们调用pub的时候,就或寻找到这个事件名,并循环将该事件名下挂载的callback队列执行。
当我们调用unsub的时候,则会将这个callback从队列中移除,这样就不会执行了。

redux的原理和这个简陋的框架类似,就是比这精巧多了,不过本质还是一样的,我们可以订阅某个值的变化,然后在某个值变化并收到这个通知的时候作出我们自己的逻辑。

接下来我们会使用redux,然后通过redux来改造这个我们的ledux,打造成至少表面上类似的......

0x005 redux栗子
import {createStore} from "redux"

// 定义一个 reducer
function counter(state = 0, action) {
    switch (action.type) {
        case "INCREMENT":
            return state + 1
        case "DECREMENT":
            return state - 1
        default:
            return state
    }
}

// 定义一个store,持有全局的 state
let store = createStore(counter)

// 订阅,并输出 state
store.subscribe(() =>
    console.log(store.getState())
)
// 发布一个事件
store.dispatch({type: "INCREMENT"})
store.dispatch({type: "INCREMENT"})
store.dispatch({type: "DECREMENT"})

查看浏览器

可以看到,其实模式差不多:

定义数据:

redux:reducer 部分

MyEvent:let num部分

订阅:

redux:subscribe 部分

MyEvent:sub部分

发布:

redux:dispatch 部分

MyEvent:pub部分

但是其实内部差别又非常大,在MyEvent中,都是很随意的,我可以随便定义事件,随便修改数据,随便发布事件,所以我写的东西叫做事件通知,而不是状态管理。redux是用来做状态管理的,可以说是在事件通知之中再一次做了封装。

MyEvent中数据是可以随意修改的,但是在redux中,数据的修改只能通过dispatch提交一个修改请求,而在reducer中处理这个请求。

0x006 ledux实现:

编写redux

class Ledux {
    static createStore(reduer) {
        return new Store(reduer)
    }
}

class Store {
    constructor(reducer) {
        this.state = reducer(null, {})
        this.callbacks = []
        this.reducer = reducer
    }

    subscribe(callback) {
        this.callbacks.push(callback)
    }

    getState() {
        return this.state
    }

    dispatch(action) {
        this.state = this.reducer(this.state, action)
        this.callbacks.forEach(callback => callback())
    }

}

export default Ledux

使用Ledix

import Ledux from "./ledux";

function counter(state = 0, action) {
    switch (action.type) {
        case "INCREMENT":
            return state + 1
        case "DECREMENT":
            return state - 1
        default:
            return state
    }
}
let store=Ledux.createStore(counter)

store.subscribe(()=>{
    console.log(store.getState())
})

store.dispatch({type: "INCREMENT"})
store.dispatch({type: "INCREMENT"})
store.dispatch({type: "DECREMENT"})

查看浏览器

可以看到,效果是一样的,而过程除了我喜欢用class封装以外也没有太大的区别,就这样实现了ledux了,当然随着对reduxapi的深入学习,这个框架也可以不断的深入发展。

0x007 资源

源码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97294.html

相关文章

  • Router入门0x201: 从 URL 到 SPA

    摘要:的全称是统一资源定位符英文,可以这么说,是一种标准,而网址则是符合标准的一种实现而已。渲染器,将组件渲染到页面上。 0x000 概述 从这一章开始就进入路由章节了,并不直接从如何使用react-route来讲,而是从路由的概念和实现来讲,达到知道路由的本质,而不是只知道如何使用react-route库的目的,毕竟react-route只是一个库,是路由的一个实现而已,而不是路由本身。 ...

    honmaple 评论0 收藏0
  • React与Redux整合技术简介

    摘要:展示组件与容器组件的绑定库的基本开发思想是展示组件与容器组件相分离。技术上讲,容器组件就是使用从树中读取部分数据,并通过来把这些数据提供给要渲染的组件。 说明:阅读本篇文章需要对Redux有一定的了解,对Redux不了解的同学可先看看这篇文章Redux技术架构简介(一) 1. React中引入react-redux 为了让Redux和React更好的配合,Facebook专门开发了一个...

    idealcn 评论0 收藏0
  • Redux技术架构简介(二)-- 异步实现

    摘要:异步实现设计需要增加三种通知异步请求发起的异步请求成功的异步请求失败的示例代码如下返回参数完全可以自定义。这种分别在请求开始前,请求成功后,请求失败后发送。表示数据的有效性,他的作用是在异步请求发送失败后,告诉当前的数据是过时的数据。 说明:对Redux不了解的同学可先看看这篇文章Redux技术架构简介(一) 前言 这里说的Redux异步实现,是专指Redux中的异步Action实现,...

    wuaiqiu 评论0 收藏0
  • react-redux插件入门

    摘要:描述这个插件可以让我们的代码更加的简洁和美观。安装使用提供了两个重要的接口使用了这个插件,的和就可以忘记来,它们就用不着了。现在有美女个。 可先查看我的redux简单入门 react-redux简介 react-redux是使用redux开发react时使用的一个插件,另外插一句,redux不是react的产品,vue和angular中也可以使用redux;下面简单讲解,如何使用rea...

    Baaaan 评论0 收藏0
  • 写一本关于 React.js 的小书

    摘要:因为工作中一直在使用,也一直以来想总结一下自己关于的一些知识经验。于是把一些想法慢慢整理书写下来,做成一本开源免费专业简单的入门级别的小书,提供给社区。本书的后续可能会做成视频版本,敬请期待。本作品采用署名禁止演绎国际许可协议进行许可 React.js 小书 本文作者:胡子大哈本文原文:React.js 小书 转载请注明出处,保留原文链接以及作者信息 在线阅读:http://huzi...

    Scorpion 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<