手写 redux 和 react-redux
1.手写 redux
redux.js
/**
* 手写 redux
*/
export function createStore(reducer) {
// 当前状态
let currentState;
// 监听队列
let currentListeners = [];
// 订阅(观察)
function subscribe(listener) {
// 将listener放入数组
currentListeners.push(listener);
// return 一个方法 取消注册
return function() {
currentListeners = currentListeners.filter(function(l) {
return l !== listener;
})
}
}
// 分发
function dispatch(action) { // 接收 action 对象
/**
* 处理完得到的结果,给当前的状态
* 执行外部传入的 render 方法
*/
currentState = reducer(currentState, action);
/**
* 将订阅者方法 挨个执行一次
*/
currentListeners.forEach((v) => v())
}
// 获取状态值
function getState() {
// 返回当前值
return currentState;
} // 返回的是个 store 对象
return {subscribe, dispatch, getState}
} /**
* 用于 react-redux 调用
*/
export function bindActionCreator(creator, dispatch) {
// 包装一下
return (...args) => {dispatch(creator(...args))}
} export function bindActionCreators(creators, dispatch) {
let bound = {};
Object.keys(creators).forEach(v => {
let creator = creators[v];
bound[v] = bindActionCreator(creator, dispatch);
}) return bound;
}
2.手写 react-redux
myReactRedux.js
/**
* 手写 react-redux
* Provider -> context 技术。可以跨级来使用属性。
*/
import React, { Component } from 'react';
// 类型检查
import PropTypes from 'prop-types';
// 引入手写的redux
import { bindActionCreators } from './redux'; // connect 方法 -- 用于获取数据
export function connect(mapStateToProps=state=>state, mapDispatchToProps={}) { // 高阶组件(方法) -- 去状态的组件
/**
* mapStateToProps 把 状态 转成 属性
* mapDispatchToProps 把 action方法 转成 属性
* react 性能优化最主要的一点是减少状态的使用,将值转为this.props的属性值来代替
*/
// 柯里化
return function(OldComponent) {
return class NewComponent extends Component {
static contextTypes = {
store: PropTypes.object // 类型与外部相同
}
// 构造函数
constructor(props, context) {
super(props, context); this.state = { // 定义内部状态
props: {
...props // 拆分符
}
};
} // 生命周期 -- 首次加载之后调用
componentDidMount(){
// 添加监听
const store = this.context.store;
store.subscribe(() => this.update());
this.update();
} update(){
const store = this.context.store;
const stateProps = mapStateToProps(store.getState()); // 把store中的数据,变为react组件的props属性
// 把原有的 action 加工, 返回 dispatch(action)
const dispatchProps = bindActionCreators(mapDispatchToProps, store.dispatch);
this.setState({
props: { // 将传入的对象的值作为props的属性
...this.state.props,
...stateProps,
...dispatchProps
} // 类型于对象合并
})
} render(){
return <OldComponent {...this.state.props} />
}
}
}
} // /**
// * 上述代码 es6 写法
// * 函数柯里化
// */
// export const connect = (mapStateToProps, mapDispatchToProps) => (OldComponent) => {
// // 接收旧的组件,返回新的组件
// return class NewComponent extends Component {
// //...
// }
// } // 创建 Provider 组件(类) -- 使得任何内容都可以直接在组件内通过 connect 使用 store
export class Provider extends Component {
// 构造函数
constructor(props, context) { // context 上下文
super(props, context); this.store = props.store; // 得到传入的store属性
}
/**
* 定义静态对象
* 类型校验 -- 确定是由哪个组件提供的store
*/
static childContextTypes = {
store: PropTypes.object
};
// 获取 child 上下文
getChildContext(){
// 向外提供,便于Provider所有子组件调用
return {store: this.store}
}
// 直接渲染Provider的子组件
render() {
return this.props.children;
}
}
3.测试
demo.js
/**
* 引入 redux
* reducer 和 action 会写在一个文件中
*/
// import { createStore } from 'redux';
import { createStore } from './redux'; // reducer
function inputChange(state = 10, action) {
switch(action.type){
case 'add': // 加
return state + 1;
case 'sub': // 减
return state - 1;
default: // 默认
return state;
}
} // 定义store
const store = createStore(inputChange); // 通过 subscribe 订阅数据流
store.subscribe(listener); // 23中设计模式 -- 观察者模式 function listener(argument) {
const current = store.getState();
console.log(`当前数据:${current}`);
} console.log(store.getState()); // 10 store.dispatch({type: 'add'}); // 11
store.dispatch({type: 'add'}); // 12
store.dispatch({type: 'sub'}); // 11 /**
* 隐式转换 -- 优先级 -- 转换顺序
* Object 高级数据结构 可以转换成 String/Boolean/Number 初级数据结构
*/
console.log({}.length); // undefined
console.log(({}+{}).length); // 30 -- string 优先级高于 number 所以变成字符串相加 -- [object Object] [object Object] 30
.
手写 redux 和 react-redux的更多相关文章
- 推荐使用并手写实现redux-actions原理
@ 目录 一.前言 二.介绍 2.1 创建action 2.2 reducer 2.3 触发action 三. 认识与手写createAction() 3.1 用法 3.2 原理实现 四.认识hand ...
- React深入 - 手写redux api
简介: 手写实现redux基础api createStore( )和store相关方法 api回顾: createStore(reducer, [preloadedState], enhancer) ...
- 手写一个Redux,深入理解其原理
Redux可是一个大名鼎鼎的库,很多地方都在用,我也用了几年了,今天这篇文章就是自己来实现一个Redux,以便于深入理解他的原理.我们还是老套路,从基本的用法入手,然后自己实现一个Redux来替代源码 ...
- react + redux 完整的项目,同时写一下个人感悟
先附上项目源码地址和原文章地址:https://github.com/bailicangd... 做React需要会什么? react的功能其实很单一,主要负责渲染的功能,现有的框架,比如angula ...
- 手写redux方法以及数组reduce方法
reduce能做什么? 1)求和 2)计算价格 3)合并数据 4)redux的compose方法 这篇文章主要内容是什么? 1)介绍reduce的主要作用 2)手写实现reduce方法 0)了解red ...
- 手写一个React-Redux,玩转React的Context API
上一篇文章我们手写了一个Redux,但是单纯的Redux只是一个状态机,是没有UI呈现的,所以一般我们使用的时候都会配合一个UI库,比如在React中使用Redux就会用到React-Redux这个库 ...
- webpack+react+redux+es6开发模式
一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...
- react+redux教程(八)连接数据库的redux程序
前面所有的教程都是解读官方的示例代码,是时候我们自己写个连接数据库的redux程序了! 例子 这个例子代码,是我自己写的程序,一个非常简单的todo,但是包含了redux插件的用法,中间件的用法,连接 ...
- react+redux教程(六)redux服务端渲染流程
今天,我们要讲解的是react+redux服务端渲染.个人认为,react击败angular的真正“杀手锏”就是服务端渲染.我们为什么要实现服务端渲染,主要是为了SEO. 例子 例子仍然是官方的计数器 ...
随机推荐
- cifar-10 图片可视化
保存cifar-10 数据集 图片 python3 #用于将cifar10的数据可视化 import pickle as p import numpy as np import matplotlib. ...
- pandas中Timestamp类用法讲解
由于网上关于Timestamp类的资料比较少,而且官网上面介绍的很模糊,本文只是对如何创建Timestamp类对象进行简要介绍,详情请读者自行查阅文档. 以下有两种方式可以创建一个Timestamp对 ...
- PAT Basic 1036
1036 跟奥巴马一起编程 美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统.2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的 ...
- 转:Ubuntu下ibus-sunpinyin的安装及翻页快捷键设置!
在windows下,好多人都已经习惯了使用搜狗拼音,到ubuntu下,忽然没有极为顺手的输入法,实为郁闷,但是确实还没有for linux版本的搜狗使用,这是搜狗的商业策略,我们无法掌控,但是,如果你 ...
- PYDay7&8-递归、冒泡算法、装饰器
1.登录验证代码 1.1纯登录验证-函数实现 def login(username,password): ''' 用于用户名密码的验证 :param username: 用户名 :param pass ...
- hdu 1536 sg (dfs实现)
S-Nim Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submi ...
- [BZOJ1590] [Usaco2008 Dec]Secret Message 秘密信息(字典树)
传送门 看到前缀就要想到字典树! 看到前缀就要想到字典树! 看到前缀就要想到字典树! #include <cstdio> #include <iostream> #define ...
- USACO Longest Prefix
题目大意:给出一个长字符串,问最长的前缀,使得这个前缀能用给出的一些元素组合而成 思路:暴力dp,dp[i]表示长度为i的前缀能否被表示 /*{ ID:a4298442 PROB:prefix LAN ...
- bzoj 5055: 膜法师 树状数组+离散
先枚举每一个数,看它前面有几个比它小,算一下和为sum1,后面有几个比它大,算一下和为sum2,对答案的贡献为A[i]*sum1*sum2. 离散化后,树状数组就可以了. 就是倒着一边,顺着一边,统计 ...
- linux命令dhclient
linux命令 dhclient 背景 多台服务器(CentOS7 系统)设置静态IP,其中有台服务器设置了静态IP后,只要重启就变更为其他的,但是配置文件并无改动. 使用命令 #自动获取IP dhc ...