内容简介:用最基础的方法讲解 Redux 实现原理?说白了其实是我能力有限,只能用最基础的方法来讲解,为了讲的更加清楚,文章可能比较拖沓。不过我相信,不是很了解 Redux 的同学,看完我今天分享的文章一定会有所收获!这不是我今天要说的重点,想知道什么是 Redux点击传送门在开始之前我想先讲一种常用的设计模式:观察者模式。先来说一下我对
用最基础的方法讲解 Redux 实现原理?说白了其实是我能力有限,只能用最基础的方法来讲解,为了讲的更加清楚,文章可能比较拖沓。不过我相信,不是很了解 Redux 的同学,看完我今天分享的文章一定会有所收获!
什么是 Redux ?
这不是我今天要说的重点,想知道什么是 Redux点击传送门
开始
在开始之前我想先讲一种常用的设计模式:观察者模式。先来说一下我对 观察者模式
的个人理解:观察者模式又称“发布-订阅(Publish/Subscribe)模式。对于这种模式很清楚的同学下面这段代码可以跳过。如果你还不清楚,你可以试着手敲一遍下面的代码!!
观察者模式
观察者模式,基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订 阅主题,通过deliver发布主题事件的方式被通知。就和用户订阅微信公众号道理一样,一个公众号可以被多个用户同时订阅,当公众号有新增内容时候,只要发布就好了,用户就能接收到最新的内容。
/** * describe: 实现一个观察者模式 */ let data = { hero: '凤凰', }; //用来储存 订阅者 的数组 let subscribers = []; //订阅 添加订阅者 方法 const addSubscriber = function(fn) { subscribers.push(fn) } //发布 const deliver = function(name) { data.hero = name; //当数据发生改变,调用(通知)所有方法(订阅者) for(let i = 0; i<subscribers.length; i++){ const fn = subscribers[i] fn() } } //通过 addSubscriber 发起订阅 addSubscriber(() => { console.log(data.hero) }) //改变data,就会自动打印名称 deliver('发条') deliver('狐狸') deliver('卡牌') 复制代码
这个发布订阅通过 addSubscriber 来储存订阅者(方法fn),当通过调用 deliver 来改变数据的时候,就会自动遍历 addSubscriber 来执行里面的 fn 方法 。
为啥要讲这个发布订阅模式呢?因为搞清楚了这个模式那么 Redux 的原理就会水到渠成。
Redux 起步
首先我们把上面那个发布订阅代码优化一下,顺便改一下命名,为什么要改命名?主要是紧跟 Redux 的步伐。让同学们更加眼熟。
let state = {hero: '凤凰'}; let subscribers = []; //订阅 定义一个 subscribe const subscribe = (fn) => { subscribers.push(fn) } //发布 const dispatch = (name) => { state.hero = name; //当数据发生改变,调用(通知)所有方法(订阅者) subscribers.forEach(fn=>fn()) } //通过 subscribe 发起订阅 subscribe(() => { console.log(state.hero) }) //改变state状态,就会自动打印名称 //这里要注意的是,state状态不能直接去修改 dispatch('发条') dispatch('狐狸') dispatch('卡牌') 复制代码
现在这样一改是不是很眼熟了,没错这就是一个类似redux改变状态的思路。但是光一个发布订阅还是不够的,不可能改变一个状态需要去定义这么多方法。所以我们把他封装起来。
creatStore 方法
const creatStore = (initState) => { let state = initState; let subscribers = []; //订阅 定义一个 subscribe const subscribe = (fn) => { subscribers.push(fn) } //发布 const dispatch = (currentState) => { state = currentState; //当数据发生改变,调用(通知)所有方法(订阅者) subscribers.forEach(fn=>fn()) } // 这里需要添加这个获取 state 的方法 const getState = () => { return state; } return { subscribe, dispatch, getState, } } 复制代码
这样就创建好了一个 createStore 方法。没有什么新东西,就传进去一个初始状态,然后在返回 subscribe, dispatch, getState 三大方法。这里新增了个 getState 方法,代码很简单就是一个 return state 为了获取 state.
creatStore 使用
实现了 createStore 下面我们来试试如何使用他,那就拿那个非常经典的案例--计数器来试试
let initState = { num: 0, } const store = creatStore(initState); //订阅 store.subscribe(() => { let state = store.getState() console.log(state.num) }) // +1 store.dispatch({ num: store.getState().num + 1 }) //-1 store.dispatch({ num: store.getState().num - 1 }) 复制代码
这个样子又接近了一点 Redux 的模样。 不过这样有个问题。如果你使用 store.dispatch 方法时,中间万一写错了或者传了个其他东西那就比较麻烦了。就比如下面这样:
其实我是想 +1,+1,-1 最后应该是 1 (初始 num 为0)!但是由于写错了一个导致后面的都会错。而且他还有个问题就是可以随便的给一个新的状态。那么就显得不那么单纯了。比如下面这样:
因为恶意修改 num 为 String 类型,导致后面在使用 dispatch 由于 num 不再是 Number 类型,导致打印出 NaN,这就不是我们想要的啦。所以我们要在改造一下,让 dispatch 变得单纯一些。那要怎么做呢?我们请一个管理者来帮我们管理,暂且给他命名 reducer
什么是 reducer
reducer 相当于是个管理者,然后我们每次想做什么就去通知管理者,让他在来根据我们说的去做。如果我们不小心说错了,那么他就不会去做。直接按默认的事情来。噔噔蹬蹬 reducer 登场!!
function reducer(state, action) { //通过传进来的 action.type 让管理者去匹配要做的事情 switch (action.type){ case 'add': return { ...state, count: state.count + 1 } case 'minus': return { ...state, count: state.count - 1 } // 没有匹配到的方法 就返回默认的值 default: return state; } } 复制代码
增加了这个管理者,那么我们就要重新来写一下之前的 createStroe 方法了:把 reducer 放进去
const creatStore = (reducer,initState) => { let state = initState; let subscribers = []; //订阅 定义一个 subscribe const subscribe = (fn) => { subscribers.push(fn) } //发布 const dispatch = (action) => { state = reducer(state,action); subscribers.forEach(fn=>fn()) } const getState = () => { return state; } return { subscribe, dispatch, getState, } } 复制代码
很简单的一个修改,为了让你们方便看出修改的地方,和区别,我特意重新码了这两个前后的方法对比,如下图
好,接下来我们试试添加了管理者的 creatStore 效果如何。
function reducer(state, action) { //通过传进来的 action.type 让管理者去匹配要做的事情 switch (action.type){ case 'add': return { ...state, num: state.num + 1 } case 'minus': return { ...state, num: state.num - 1 } // 没有匹配到的方法 就返回默认的值 default: return state; } } let initState = { num: 0, } const store = creatStore(reducer,initState); //订阅 store.subscribe(() => { let state = store.getState() console.log(state.num) }) 复制代码
为了看清楚结果,dispatch(订阅)我直接再控制台输出,如下图:
效果很好,我们不会再因为写错,而出现 NaN 或者其他不可描述的问题。现在这个 dispatch 比较纯粹了一点。
我们只是给他一个 type ,然后让管理者自己去帮我们处理如何更改状态。如果不小心写错,或者随便给个 type 那么管理者匹配不到那么这个动作那么我们这次 dispatch 就是无效的,会返回我们自己的默认 state。
好叻,现在这个样子基本上就是我脑海中第一次使用 redux 看到的样子。那个时候我使用起来都非常困难。当时勉强实现了一下这个计数器 demo 我就默默的关闭了 vs code。
接下来我们再完善一下这个 reducer,给他再添加一个方法。并且这次我们再给 state 一个
function reducer(state, action) { //通过传进来的 action.type 让管理者去匹配要做的事情 switch (action.type){ case 'add': return { ...state, num: state.num + 1 } case 'minus': return { ...state, num: state.num - 1 } // 增加一个可以传参的方法,让他更加灵活 case 'changeNum': return { ...state, num: state.num + action.val } // 没有匹配到的方法 就返回默认的值 default: return state; } } let initState = { num: 0, } const store = creatStore(reducer,initState); //订阅 store.subscribe(() => { let state = store.getState() console.log(state.num) }) 复制代码
控制台再使用一次新的方法:
好叻,这样是不是就让 dispatch 更加灵活了。
现在我们再 reducer 中就写了 3 个方法,但是实际项目中,方法一定是很多的,那么都这样写下去,一定是不利于开发和维护的。那么这个问题就留给大家去思考一下。
提示:Redux 也知道这一点,所以他提供了 combineReducers
去实现这个模式。这是一个高阶 Reducer 的示例,他接收一个拆分后 reducer 函数组成的对象,返回一个新的 Reducer 函数。
思考完之后可以参考redux 中文文档 的combineReducers介绍
具体实现原理我将会在下次分享。
总结
Redux 这个项目里,有很多非常巧妙的方法,很多地方可以借鉴。毕竟这可是在 github 上又 47W+ 的 Star。
今天也只是讲了他的一小部分。自己也在努力学习中,希望今后能分享更多的看法,并和大家深入探讨。
以上所述就是小编给大家介绍的《用最基础的方法讲解 Redux 实现原理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Webpack原理简单讲解
- Haproxy原理与配置讲解
- 深入浅出讲解HTTPS工作原理
- SVM | 支持向量机原理讲解(二)
- JVM基础面试题及原理讲解
- Hadoop 学习系列(四)之 MapReduce 原理讲解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python编程
[美]埃里克·马瑟斯 / 袁国忠 / 人民邮电出版社 / 2016-7-1 / CNY 89.00
本书是一本针对所有层次的Python 读者而作的Python 入门书。全书分两部分:第一部分介绍用Python 编程所必须了解的基本概念,包括matplotlib、NumPy 和Pygal 等强大的Python 库和工具介绍,以及列表、字典、if 语句、类、文件与异常、代码测试等内容;第二部分将理论付诸实践,讲解如何开发三个项目,包括简单的Python 2D 游戏开发如何利用数据生成交互式的信息图......一起来看看 《Python编程》 这本书的介绍吧!