手写实现redux,react-redux的api,中间件原理

redux源码参考
准备工作

首先建一个React的脚手架项目, 删除src下的所有东西,保留一个空的 index.js

当前目录
index.html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div id="root"></div></body>
</html>

src/ index.js

// 空 的js

需求1:js 实现渲染(风影嘎拉)三个字到 div 容器中

let state = {name: '风影嘎拉',color: '#f00',
}
function render(obj) {const dom = document.getElementById('root')dom.innerHTML = obj.namedom.style.color = obj.color
}
render(state)

启动服务:

当前的设计呢,存在诸多问题, 比如 state 变量谁都可以更改,不安全, 而每次更改时,不同的人可能会更改不同的值,
那么,是不是可以通过派发动作的方式,来改变具体的属性, 比如只改变名字, 只改变颜色, 接着下边改进

  1. 改成通过派发一个动作,让状态改变,一个动作干一件事
let state = {name: '风影嘎拉',color: '#f00',
}function render(obj) {const dom = document.getElementById('root')dom.innerHTML = obj.namedom.style.color = obj.color
}// 添加动态改写逻辑
const CHANGE_NAME = 'CHANGE_NAME'
const CHANGE_COLOR = 'CHANGE_COLOR'
function dispatch(action) {switch (action.type) {case CHANGE_NAME:state.name = '手鞠'breakcase CHANGE_COLOR:state.color = action.colorbreakdefault:break}
}
// 派发动作改变名字
dispatch({ type: CHANGE_NAME })
//派发动作改变颜色, 并传参
dispatch({ type: CHANGE_COLOR, color: 'green' })
render(state)


虽然改进了,一个动作做一件事, 但还是那个问题,全局的state 变量可以随意更改,
比如说,我可以手动把state 的值置位 null, 这显然是不合理的, 我希望变量能私有化

变量私有化, 可以采用 IIFE 函数(明显此处不合适), 也可以采用函数闭包的形势

创建一个 createStore 方法, 用来创建数据源

function render(obj) {const dom = document.getElementById('root')dom.innerHTML = obj.namedom.style.color = obj.color
}// 添加动态改写逻辑
const CHANGE_NAME = 'CHANGE_NAME'/**** 进行变量私有化* 函数,闭包*/
function createStore() {let store = {name: '风影嘎啦',color: '#f26',}// 获取状态function getState() {return store }// 派发动作改变数据源function dispatch(action) {switch (action.type) {case CHANGE_NAME:store.name = '手鞠'breakdefault:break}}// 导出return {getState,dispatch,}
}
// 创建 store 数据源
let store = createStore()// 派发 action 改变名字
store.dispatch({type: CHANGE_NAME,
})
// 调用 store.getState() 获取数据源
render(store.getState())


到这里,前边的问题算是解决了, 但是又有一个新问题了,状态外部无法改变,内部直接写死了,简单画个草图

此时,A, B, C 三个组件,可能每个组件都有自己的特有的数据源,但此时的数据源可能只适合 A 组件
所以,截下来要解决的问题就是,能动态的数据源, 固定的输入,得到固定的输出

  1. 在 createStore() 方法时,传入一个纯函数
  2. 解决数据状态由用户自己具体指定
  3. 固定的输入,得到固定的输出
function render(obj) {const dom = document.getElementById('root')dom.innerHTML = obj.namedom.style.color = obj.color
}/**** 进行变量私有化* 函数,闭包*/function createStore(reducer) {// 默认初始状态let state// 得到总的状态树function getState() {return state}// 派发动作function dispatch(action) {// 得到新状态state = reducer(state, action)}// 由于默认 state 树是没有状态的, 是一个控制,所以先派发一次action,给初始状态赋值,// 由于用户自己定义的reducer 默认返回初始状态,由于派发的这个type类型找不到,所以默认返回了初始值dispatch({ type: '@@REDUX_INIT' })return {getState,dispatch,}
}// 初始状态
let initState = {name: '我爱罗',color: '#f26',
}// 添加动态改写逻辑
const CHANGE_NAME = 'CHANGE_NAME'
// 状态用户自己定义,传入老的状态,返回新状态
function reducer(state = initState, action) {switch (action.type) {case CHANGE_NAME:return {...state,name: action.name,}default:return state}
}
// 得到数据源
let store = createStore(reducer)
// 派发action动作
store.dispatch({type: CHANGE_NAME,name: '7代目止水',
})render(store.getState())


此时,基本实现了简化版redux, 然而还有一个问题, 就是如果你先渲染,然后再派发动作的话, 视图是不会改变的,你只能先派发action , 才会立马更新视图

let store = createStore(reducer)
// 如果在这不会视图更新
render(store.getState())
store.dispatch({type: CHANGE_NAME,name: '手鞠',
})
// 如果先派发动作,视图会更新
// render(store.getState())

那如果我就想先渲染更新,接着再渲染后,继续提交action,还要引起视图的更新,就像上边代码一样,先渲染,再render

此时可以使用发布订阅模式,来监听你的改变
一个简单的发布订阅模式:

接着实现发布订阅,那既然可以订阅, 就可以取消订阅

function render(obj) {const dom = document.getElementById('root')dom.innerHTML = obj.namedom.style.color = obj.color
}/**** 进行变量私有化* 函数,闭包*/function createStore(reducer) {// 默认初始状态let statelet listeners = [] // 存储所有的监听函数// 得到总的状态树function getState() {return state}// 派发动作function dispatch(action) {// 得到新状态state = reducer(state, action)// 订阅listeners.forEach((fn) => fn())}// 由于默认 state 树是没有状态的, 是一个控制,所以先派发一次action,给初始状态赋值,// 由于用户自己定义的reducer 默认返回初始状态,由于派发的这个type类型找不到,所以默认返回了初始值dispatch({ type: '@@REDUX_INIT' })// 添加发布订阅模式function subscribe(listener) {listeners.push(listener)// 返回一个取消订阅方法(就是个高阶函数)return function () {listeners = listeners.filter((fn) => fn !== listener)}}return {getState,dispatch,subscribe,}
}
let app = {name: '我爱罗',color: '#f26',
}// 添加动态改写逻辑
const CHANGE_NAME = 'CHANGE_NAME'
const CHANGE_COLOR = 'CHANGE_COLOR'function reducer(state = app, action) {switch (action.type) {case CHANGE_NAME:return {...state,name: action.name,}case CHANGE_COLOR:return {...state,color: action.color,}default:return state}
}let store = createStore(reducer)// 必选先派发action , 再去触发渲染,不能先渲染,再派发动作
/*** 解决办法: 添加发布订阅模式*/
const AppRender = () => render(store.getState())// 先调用渲染一次
AppRender()let unSubscribe = store.subscribe(AppRender)// 模拟延时渲染
setTimeout(() => {store.dispatch({type: CHANGE_NAME,name: '手鞠',})// 取消订阅, 下边的不会在执行了// unSubscribe()store.dispatch({type: CHANGE_COLOR,color: 'blue',})
}, 1500)

最后总结代码也就20多行吧,暴露出3个api

function createStore(reducer) {let statelet listeners = []function getState() {return state}function dispatch(action) {state = reducer(state, action)listeners.forEach((fn) => fn())}dispatch({ type: '@@REDUX_INIT' })function subscribe(listener) {listeners.push(listener)return function () {listeners = listeners.filter((fn) => fn !== listener)}}return {getState,dispatch,subscribe,}
}

redux1 - 20行代码实现redux相关推荐

  1. 20行代码发一篇NeurIPS:梯度共享已经不安全了

    整理 | 夕颜,Jane 出品 | AI科技大本营(ID:rgznai100) [导读]12 月 8 日-14 日,NeurIPS 2019 在加拿大温哥华举行,和往常一样,今年大会吸引了数万名专家参 ...

  2. php横排代码,20行代码原生js实现文字横向轮播

    20行代码实现文字横向轮播效果 1 页面布局代码 恭喜793765***获得 50元超市充值卡卡奖励 恭喜793765***获得 50元超市充值卡卡奖励 恭喜793765***获得 50元超市充值卡卡 ...

  3. 《看聊天记录都学不会C语言?太菜了吧》(14)这么神奇?我写了20行代码竟然一行就可以搞定?

    好消息2020年4月13日晚7.30我在CSDN开播,等你来聊天 预约连接:https://live.csdn.net/room/A757291228/MJWK0Gem 本系列文章将会以通俗易懂的对话 ...

  4. Python用20行代码实现一个验证码的输入与验证(完整源码)

    我们平常上网处处可见需要输入验证码的地方,利用Python的random()模块,其实我们只用简单20行代码就能实现.下为效果图,能识别是否正确: 其中也没有复杂的函数嵌套.函数递归,逻辑也比较简单, ...

  5. Python用20行代码实现完整邮件功能 [完整代码+建议收藏]

    大家好,我是Lex 喜欢欺负超人那个Lex 擅长领域:python开发.网络安全渗透.Windows域控Exchange架构 今日重点:python脚本实现发送邮件,邮件添加附件,读取接收邮件等功能. ...

  6. 女神相册密码忘记了,我只用Python写了20行代码

    ​视频地址 我用20行代码,帮女神破解相册密码 一.事情是这样的 今早上班,公司女神小姐姐说,她去年去三亚旅游的照片打不开了 好奇问了一下才知道. 原来是,她把照片压缩了,而且还加了密码. 但是密码不 ...

  7. python黑科技:Python大佬用20行代码带你打造一个微信聊天机器人,真神了~

    如何用20行Python代码打造一个微信群聊助手? 1.安装python环境 2.安装python的itchat库 3.安装itchat库 4.Linux 5.申请图灵机器人API和key 6.编写p ...

  8. C# 20行代码解析KRC歌词内容

    C# 20行代码解析KRC歌词内容 文章内容仅供学习参考,禁止转载. KRC 歌词文件支持了逐字精准,解决了一行歌词进度显示不准确的问题.由此好奇其存储歌词的方式,于是参考网络其他资料总结如下: KR ...

  9. python人物抠图算法_比PS还好用!Python 20行代码批量抠图

    抠图前 vs Python自动抠图后 在日常的工作和生活中,我们经常会遇到需要抠图的场景,即便是只有一张图片需要抠,也会抠得我们不耐烦,倘若遇到许多张图片需要抠,这时候你的表情应该会很有趣. Pyth ...

最新文章

  1. 利用反射自己写的一个ModelHelper类
  2. Java排序算法之归并排序
  3. java中接口适配器实现,12.1.8 Java中的应用-AWT事件适配器(接口的适配器模式)...
  4. AnyChat SDK支持哪些开发语言?
  5. 职场上个人的核心技术_职场上,靠谱比聪明更重要:如何做一个靠谱的人
  6. 调试阶段 获取微信小程序openid
  7. php通过post请求_php代码post请求
  8. 提取pdf文件文本:pdfparser与xpdf具体操作
  9. Ubuntu、SUSE的发音
  10. DM 跟踪日志及ET
  11. 苹果手机怎么修改dns服务器,苹果手机怎么设置DNS iPhone8更改DNS详细图文教程
  12. 学校机房计算机类型,学校计算机机房的管理和维护建议原稿(备份存档)
  13. 案例分享:Qt modbus485调试工具(读写Byte、Int、DInt、Real、DReal)(当前v1.3.0)
  14. 四方伟业冲刺科创板:年营收为2.8亿 南威软件与文化基金是股东
  15. win查看服务器主板型号,Win10怎么看电脑主板型号?
  16. python爬虫视频教程
  17. 2020移动apn接入点哪个快_设置APN教程
  18. 学习大数据需要什么基础?大数据要学哪些内容?
  19. 2006年100首好歌
  20. 代码写成这样,老夫无可奈何!

热门文章

  1. Android中浮窗的开发详述
  2. AnyLink Vpn办公网部署,用于安全办公
  3. 一张图带你看懂电脑玩《和平精英》智能操作键位
  4. 程序员对自己的认同的一些思考
  5. vue-element-admin改造顶部一级导航,侧边二级导航
  6. PHP输出缓冲(Output Buffering)
  7. 浅谈CSS3中的content-box和border-box的区别
  8. 百货商场会员营销/购物中心会员系统经典案例
  9. LUA 魔兽世界 上线送技能
  10. vue 的浅拷贝和深拷贝