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
.