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的更多相关文章

  1. 推荐使用并手写实现redux-actions原理

    @ 目录 一.前言 二.介绍 2.1 创建action 2.2 reducer 2.3 触发action 三. 认识与手写createAction() 3.1 用法 3.2 原理实现 四.认识hand ...

  2. React深入 - 手写redux api

    简介: 手写实现redux基础api createStore( )和store相关方法 api回顾: createStore(reducer, [preloadedState], enhancer) ...

  3. 手写一个Redux,深入理解其原理

    Redux可是一个大名鼎鼎的库,很多地方都在用,我也用了几年了,今天这篇文章就是自己来实现一个Redux,以便于深入理解他的原理.我们还是老套路,从基本的用法入手,然后自己实现一个Redux来替代源码 ...

  4. react + redux 完整的项目,同时写一下个人感悟

    先附上项目源码地址和原文章地址:https://github.com/bailicangd... 做React需要会什么? react的功能其实很单一,主要负责渲染的功能,现有的框架,比如angula ...

  5. 手写redux方法以及数组reduce方法

    reduce能做什么? 1)求和 2)计算价格 3)合并数据 4)redux的compose方法 这篇文章主要内容是什么? 1)介绍reduce的主要作用 2)手写实现reduce方法 0)了解red ...

  6. 手写一个React-Redux,玩转React的Context API

    上一篇文章我们手写了一个Redux,但是单纯的Redux只是一个状态机,是没有UI呈现的,所以一般我们使用的时候都会配合一个UI库,比如在React中使用Redux就会用到React-Redux这个库 ...

  7. webpack+react+redux+es6开发模式

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  8. react+redux教程(八)连接数据库的redux程序

    前面所有的教程都是解读官方的示例代码,是时候我们自己写个连接数据库的redux程序了! 例子 这个例子代码,是我自己写的程序,一个非常简单的todo,但是包含了redux插件的用法,中间件的用法,连接 ...

  9. react+redux教程(六)redux服务端渲染流程

    今天,我们要讲解的是react+redux服务端渲染.个人认为,react击败angular的真正“杀手锏”就是服务端渲染.我们为什么要实现服务端渲染,主要是为了SEO. 例子 例子仍然是官方的计数器 ...

随机推荐

  1. VS搭建一个WEB的简历第二天,,,最终目标写个好看的简历,再搭建一个自己脑海的网页

    VS做简历的第二天 第二天吸取了第一天的教训写的代码 第一天写的代码https://www.cnblogs.com/pythonywy/p/10816215.html,写了一堆错误T T 非常感谢Li ...

  2. python 实现计算器功能 输入字符串,输出相应结果

    import re formul='1 - 2 *( (6 0- 30+(0-40/5) * (9-2* 5/3 +7 /3*99/4*2998 +10 *568/14)) - (-4*3) / (1 ...

  3. inode结构体

    inode分为内存中的inode和文件系统中的inode,为了避免混淆,我们称前者为VFS inode, 而后者以EXT2为代表,我们称为Ext2 inod.这里说明的是VFS inode. 重要成员 ...

  4. LeetCode(116) Populating Next Right Pointers in Each Node

    题目 Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode * ...

  5. python中split()函数讲解

    本文讲述的是string.split(s[, sep[, maxsplit]]),针对string类型的split()函数.它主要是切割字符串,结果返回由字符串元素组成的一个列表,具体怎么使用看下面的 ...

  6. PAT Basic 1029

    1029 旧键盘 旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及实际被输入的文字,请你列出肯定坏掉的那些键. 输入格式: 输入在2行中分别给出应该输 ...

  7. APP版本升级

    /*** version_upgrade 版本升级信息表*/CREATE TABLE `version_upgrade` ( `id` smallint(4) unsigned NOT NULL AU ...

  8. n&(n-1)的用途

    最近做LeetCode上面的题目,发现很多题目都用到了n&(n-1).感觉真是神通广大,下面就目前所看到的一些用途总结一下: 1,求一个int类型数是否为2的幂 当n=4时,二进制为:0100 ...

  9. AVPlayerViewController视频播放器

    前言 iOS8之后系统自带使用AVPlayerViewController播放视频 AVPlayerViewController AVPlayerViewController和导航控制器差不多,需要将 ...

  10. 【Luogu】P1967货车运输(最大生成森林+倍增LCA)

    题目链接 倍增LCA是个什么蛇皮原理啊,循环完了还得再往上跳一次才能到最近公共祖先 合着我昨天WA两次就是因为这个 建最大生成森林,因为图不一定是联通的,所以不一定是一棵树.这个地方用克鲁斯卡尔就好了 ...