24行JavaScript代码实现Redux的方法实例


Posted in Javascript onNovember 17, 2019

前言

Redux是迄今为止创建的最重要的JavaScript库之一,灵感来源于以前的艺术比如Flux和Elm,Redux通过引入一个包含三个简单要点的可伸缩体系结构,使得JavaScript函数式编程成为可能。如果你是初次接触Redux,可以考虑先阅读官方文档。

1. Redux大多是规约

考虑如下这个使用了Redux架构的简单的计数器应用。如果你想跳过的话可以直接查看Github Repo。

1.1 State存储在一棵树中

该应用程序的状态看起来如下:

const initialState = { count: 0 };

1.2 Action声明状态更改

根据Redux规约,我们不直接修改(突变)状态。

// 在Redux应用中不要做如下操作
state.count = 1;

相反,我们创建在应用中用户可能用到的所有行为。

const actions = {
 increment: { type: 'INCREMENT' },
 decrement: { type: 'DECREMENT' }
};

1.3 Reducer解释行为并更新状态

在最后一个架构部分我们叫做Reduer,其作为一个纯函数,它基于以前的状态和行为返回状态的新副本。

  • 如果increment被触发,则增加state.count
  • 如果decrement被触发,则减少state.count
const countReducer = (state = initialState, action) => {
 switch (action.type) {
 case actions.increment.type:
  return {
  count: state.count + 1
  };

 case actions.decrement.type:
  return {
  count: state.count - 1
  };

 default:
  return state;
 }
};

1.4 目前为止还没有Redux

你注意到了吗?到目前为止我们甚至还没有接触到Redux库,我们仅仅只是创建了一些对象和函数,这就是为什么我称其为"大多是规约",90%的Redux应用其实并不需要Redux。

2. 开始实现Redux

要使用这种架构,我们必须要将它放入到一个store当中,我们将仅仅实现一个函数:createStore。使用方式如下:

import { createStore } from 'redux'

const store = createStore(countReducer);

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

store.dispatch(actions.increment);
// logs { count: 1 }

store.dispatch(actions.increment);
// logs { count: 2 }

store.dispatch(actions.decrement);
// logs { count: 1 }

下面这是我们的初始化样板代码,我们需要一个监听器列表listeners和reducer提供的初始化状态。

const createStore = (yourReducer) => {
 let listeners = [];
 let currentState = yourReducer(undefined, {});
}

无论何时某人订阅了我们的store,那么他将会被添加到listeners数组中。这是非常重要的,因为每次当某人在派发(dispatch)一个动作(action)的时候,所有的listeners都需要在此次事件循环中被通知到。调用yourReducer函数并传入一个undefined和一个空对象将会返回一个initialState,这个值也就是我们在调用store.getState()时的返回值。既然说到这里了,我们就来创建这个方法。

2.1 store.getState()

这个函数用于从store中返回最新的状态,当用户每次点击一个按钮的时候我们都需要最新的状态来更新我们的视图。

const createStore = (yourReducer) => {
 let listeners = [];
 let currentState = yourReducer(undefined, {});
 
 return {
  getState: () => currentState
 };
}

2.2 store.dispatch()

这个函数使用一个action作为其入参,并且将这个action和currentState反馈给yourReducer来获取一个新的状态,并且dispatch方法还会通知到每一个订阅了当前store的监听者。

const createStore = (yourReducer) => {
 let listeners = [];
 let currentState = yourReducer(undefined, {});

 return {
 getState: () => currentState,
 dispatch: (action) => {
  currentState = yourReducer(currentState, action);

  listeners.forEach((listener) => {
  listener();
  });
 }
 };
};

2.3 store.subscribe(listener)

这个方法使得你在当store接收到一个action的时候能够被通知到,可以在这里调用store.getState()来获取最新的状态并更新UI。

const createStore = (yourReducer) => {
 let listeners = [];
 let currentState = yourReducer(undefined, {});

 return {
 getState: () => currentState,
 dispatch: (action) => {
  currentState = yourReducer(currentState, action);

  listeners.forEach((listener) => {
  listener();
  });
 },
 subscribe: (newListener) => {
  listeners.push(newListener);

  const unsubscribe = () => {
  listeners = listeners.filter((l) => l !== newListener);
  };

  return unsubscribe;
 }
 };
};

同时subscribe函数返回了另一个函数unsubscribe,这个函数允许你当不再对store的更新感兴趣的时候能够取消订阅。

3. 整理代码

现在我们添加按钮的逻辑,来看看最后的源代码:

// 简化版createStore函数
const createStore = (yourReducer) => {
 let listeners = [];
 let currentState = yourReducer(undefined, {});

 return {
 getState: () => currentState,
 dispatch: (action) => {
  currentState = yourReducer(currentState, action);

  listeners.forEach((listener) => {
  listener();
  });
 },
 subscribe: (newListener) => {
  listeners.push(newListener);

  const unsubscribe = () => {
  listeners = listeners.filter((l) => l !== newListener);
  };

  return unsubscribe;
 }
 };
};

// Redux的架构组成部分
const initialState = { count: 0 };

const actions = {
 increment: { type: 'INCREMENT' },
 decrement: { type: 'DECREMENT' }
};

const countReducer = (state = initialState, action) => {
 switch (action.type) {
 case actions.increment.type:
  return {
  count: state.count + 1
  };

 case actions.decrement.type:
  return {
  count: state.count - 1
  };

 default:
  return state;
 }
};

const store = createStore(countReducer);

// DOM元素
const incrementButton = document.querySelector('.increment');
const decrementButton = document.querySelector('.decrement');

// 给按钮添加点击事件
incrementButton.addEventListener('click', () => {
 store.dispatch(actions.increment);
});

decrementButton.addEventListener('click', () => {
 store.dispatch(actions.decrement);
});

// 初始化UI视图
const counterDisplay = document.querySelector('h1');
counterDisplay.innerHTML = parseInt(initialState.count);

// 派发动作的时候跟新UI
store.subscribe(() => {
 const state = store.getState();

 counterDisplay.innerHTML = parseInt(state.count);
});

我们再次看看最后的视图效果:

24行JavaScript代码实现Redux的方法实例

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

原文: https://www.freecodecamp.org/news/redux-in-24-lines-of-code/

作者:Yazeed Bzadough

译者:小维FE

Javascript 相关文章推荐
javascript中字符串替换函数replace()方法与c# 、vb 替换有一点不同
Jun 25 Javascript
给jqGrid数据行添加修改和删除操作链接(之一)
Nov 04 Javascript
一个背景云变换js特效 鼠标移动背景云变化
Dec 28 Javascript
用Javascript来生成ftp脚本的小例子
Jul 03 Javascript
jQuery实现html元素拖拽
Jul 21 Javascript
jquery实现简易的移动端验证表单
Nov 08 Javascript
悬浮广告方法日常收集整理
Mar 18 Javascript
微信小程序 用户数据解密详细介绍
Jan 09 Javascript
jQuery插件FusionCharts绘制的2D条状图效果【附demo源码】
May 13 jQuery
vue根据进入的路由进行原路返回的方法
Sep 26 Javascript
JS控制只能输入数字并且最多允许小数点两位
Nov 24 Javascript
使用konva和vue-konva库实现拖拽滑块验证功能
Apr 27 Javascript
JavaScript如何处理移动端拍摄图片旋转问题
Nov 16 #Javascript
JS Ajax请求会话过期处理问题解决方法分析
Nov 16 #Javascript
vue中注册自定义的全局js方法
Nov 15 #Javascript
微信sdk实现禁止微信分享(使用原生php实现)
Nov 15 #Javascript
微信JSSDK实现打开摄像头拍照再将相片保存到服务器
Nov 15 #Javascript
微信小程序自定义导航栏(模板化)
Nov 15 #Javascript
在node环境下parse Smarty模板的使用示例代码
Nov 15 #Javascript
You might like
redis 队列操作的例子(php)
2012/04/12 PHP
深入理解:单一入口、MVC、ORM、CURD、ActiveRecord概念
2013/06/06 PHP
PHP fastcgi模式上传大文件(大约有300多K)报错
2014/09/28 PHP
ThinkPHP实现生成和校验验证码功能
2017/04/28 PHP
PHP7变量处理机制修改
2021/03/09 PHP
ASP.NET jQuery 实例3 (在TextBox里面阻止复制、剪切和粘贴事件)
2012/01/13 Javascript
javascript实现存储hmtl字符串示例
2014/04/25 Javascript
jQuery简单创建节点的方法
2016/09/09 Javascript
详解React-Todos入门例子
2016/11/08 Javascript
基于JavaScript实现本地图片预览
2017/02/08 Javascript
Kindeditor单独调用单图上传增加预览功能的实例
2017/07/31 Javascript
在vue中读取本地Json文件的方法
2018/09/06 Javascript
解决angularJS中input标签的ng-change事件无效问题
2018/09/13 Javascript
layui table 列宽百分比显示的实现方法
2019/09/28 Javascript
解决vue.js提交数组时出现数组下标的问题
2019/11/05 Javascript
详解JavaScript中的Object.is()与"==="运算符总结
2020/06/17 Javascript
解决vue-router 切换tab标签关闭时缓存问题
2020/07/22 Javascript
vue组件是如何解析及渲染的?
2021/01/13 Vue.js
介绍Python中的__future__模块
2015/04/27 Python
Python基于动态规划算法解决01背包问题实例
2017/12/06 Python
python装饰器深入学习
2018/04/06 Python
python使用__slots__让你的代码更加节省内存
2018/09/05 Python
Python中的 sort 和 sorted的用法与区别
2019/08/10 Python
python pandas利用fillna方法实现部分自动填充功能
2020/03/16 Python
Python实现自动打开电脑应用的示例代码
2020/04/17 Python
PyQt5 文本输入框自动补全QLineEdit的实现示例
2020/05/13 Python
亚马逊新加坡官方网站:Amazon.sg
2020/03/25 全球购物
体育学院毕业生自荐信
2013/11/03 职场文书
文科教师毕业的自我评价
2014/01/16 职场文书
养生餐厅创业计划书范文
2014/03/26 职场文书
全国税务系统先进集体事迹材料
2014/05/19 职场文书
党员志愿者活动总结
2014/06/26 职场文书
小学三好学生事迹材料
2014/08/15 职场文书
2016春季小学开学寄语
2015/12/03 职场文书
python脚本框架webpy模板赋值实现
2021/11/20 Python
Python实现归一化算法详情
2022/03/18 Python