导航菜单

  • 0.api
  • 0.Async
  • 0.module
  • 1.ES2015
  • 2.Promise
  • 3.Node
  • 4.NodeInstall
  • 5.REPL
  • 6.NodeCore
  • 7.module&NPM
  • 8.Encoding
  • 9.Buffer
  • 10.fs
  • 11.Stream-1
  • 11.Stream-2
  • 11.Stream-3
  • 11.Stream-4
  • 12-Network-2
  • 12.NetWork-3
  • 12.Network-1
  • 13.tcp
  • 14.http-1
  • 14.http-2
  • 15.compress
  • 16.crypto
  • 17.process
  • 18.yargs
  • 19.cache
  • 20.action
  • 21.https
  • 22.cookie
  • 23.session
  • 24.express-1
  • 24.express-2
  • 24.express-3
  • 24.express-4
  • 25.koa-1
  • 26.webpack-1-basic
  • 26.webpack-2-optimize
  • 26.webpack-3-file
  • 26.webpack-4.tapable
  • 26.webpack-5-AST
  • 26.webpack-6-sources
  • 26.webpack-7-loader
  • 26.webpack-8-plugin
  • 26.webpack-9-hand
  • 26.webpack-10-prepare
  • 28.redux
  • 28.redux-jwt-back
  • 28.redux-jwt-front
  • 29.mongodb-1
  • 29.mongodb-2
  • 29.mongodb-3
  • 29.mongodb-4
  • 29.mongodb-5
  • 29.mongodb-6
  • 30.cms-1-mysql
  • 30.cms-2-mysql
  • 30.cms-3-mysql
  • 30.cms-4-nunjucks
  • 30.cms-5-mock
  • 30.cms-6-egg
  • 30.cms-7-api
  • 30.cms-8-roadhog
  • 30.cms-9-yaml
  • 30.cms-10-umi
  • 30.cms-12-dva
  • 30.cms-13-dva-ant
  • 30.cms-14-front
  • 30.cms-15-deploy
  • 31.dva
  • 31.cms-13-dva-antdesign
  • 33.redis
  • 34.unittest
  • 35.jwt
  • 36.websocket-1
  • 36.websocket-2
  • 38.chat-api-1
  • 38.chat-api-2
  • 38.chat-3
  • 38.chat-api-3
  • 38.chat
  • 38.chat2
  • 38.chat2
  • 39.crawl-0
  • 39.crawl-1
  • 39.crawl-2
  • 40.deploy
  • 41.safe
  • 42.test
  • 43.nginx
  • 44.enzyme
  • 45.docker
  • 46.elastic
  • 47.oauth
  • 48.wxpay
  • index
  • 52.UML
  • 53.design
  • index
  • 54.linux
  • 57.ts
  • 56.react-ssr
  • 58.ts_react
  • 59.ketang
  • 59.ketang2
  • 61.1.devops-linux
  • 61.2.devops-vi
  • 61.3.devops-user
  • 61.4.devops-auth
  • 61.5.devops-shell
  • 61.6.devops-install
  • 61.7.devops-system
  • 61.8.devops-service
  • 61.9.devops-network
  • 61.10.devops-nginx
  • 61.11.devops-docker
  • 61.12.devops-jekins
  • 61.13.devops-groovy
  • 61.14.devops-php
  • 61.15.devops-java
  • 61.16.devops-node
  • 61.17.devops-k8s
  • 62.1.react-basic
  • 62.2.react-state
  • 62.3.react-high
  • 62.4.react-optimize
  • 62.5.react-hooks
  • 62.6.react-immutable
  • 62.7.react-mobx
  • 62.8.react-source
  • 63.1.redux
  • 63.2.redux-middleware
  • 63.3.redux-hooks
  • 63.4.redux-saga
  • 63.5.redux-saga-hand
  • 64.1.router
  • 64.2.router-connected
  • 65.1.typescript
  • 65.2.typescript
  • 65.3.typescript
  • 65.4.antd
  • 65.4.definition
  • 66-1.vue-base
  • 66-2.vue-component
  • 66-3.vue-cli3.0
  • 66-4.$message组件
  • 66-5.Form组件
  • 66-6.tree
  • 66-7.vue-router-apply
  • 66-8.axios-apply
  • 66-9.vuex-apply
  • 66-10.jwt-vue
  • 66-11.vue-ssr
  • 66-12.nuxt-apply
  • 66-13.pwa
  • 66-14.vue单元测试
  • 66-15.权限校验
  • 67-1-network
  • 68-2-wireshark
  • 7.npm2
  • 69-hooks
  • 70-deploy
  • 71-hmr
  • 72.deploy
  • 73.import
  • 74.mobile
  • 75.webpack-1.文件分析
  • 75.webpack-2.loader
  • 75.webpack-3.源码流程
  • 75.webpack-4.tapable
  • 75.webpack-5.prepare
  • 75.webpack-6.resolve
  • 75.webpack-7.loader
  • 75.webpack-8.module
  • 75.webpack-9.chunk
  • 75.webpack-10.asset
  • 75.webpack-11.实现
  • 76.react_optimize
  • 77.ts_ketang_back
  • 77.ts_ketang_front
  • 78.vue-domdiff
  • 79.grammar
  • 80.tree
  • 81.axios
  • 82.1.react
  • 82.2.react-high
  • 82.3.react-router
  • 82.4.redux
  • 82.5.redux_middleware
  • 82.6.connected
  • 82.7.saga
  • 82.8.dva
  • 82.8.dva-source
  • 82.9.roadhog
  • 82.10.umi
  • 82.11.antdesign
  • 82.12.ketang-front
  • 82.12.ketang-back
  • 83.upload
  • 84.graphql
  • 85.antpro
  • 86.1.uml
  • 86.2.design
  • 87.postcss
  • 88.react16-1
  • 89.nextjs
  • 90.react-test
  • 91.react-ts
  • 92.rbac
  • 93.tsnode
  • 94.1.JavaScript
  • 94.2.JavaScript
  • 94.3.MODULE
  • 94.4.EventLoop
  • 94.5.文件上传
  • 94.6.https
  • 94.7. nginx
  • 95.1. react
  • 95.2.react
  • 96.1.react16
  • 96.2.fiber
  • 96.3.fiber
  • 97.serverless
  • 98.websocket
  • 100.1.react-basic
  • 101.1.monitor
  • 101.2.monitor
  • 102.java
  • 103.1.webpack-usage
  • 103.2.webpack-bundle
  • 103.3.webpack-ast
  • 103.4.webpack-flow
  • 103.5.webpack-loader
  • 103.6.webpack-tapable
  • 103.7.webpack-plugin
  • 103.8.webpack-optimize1
  • 103.9.webpack-optimize2
  • 103.10.webpack-hand
  • 103.11.webpack-hmr
  • 103.11.webpack5
  • 103.13.splitChunks
  • 103.14.webpack-sourcemap
  • 103.15.webpack-compiler1
  • 103.15.webpack-compiler2
  • 103.16.rollup.1
  • 103.16.rollup.2
  • 103.16.rollup.3
  • 103.16.vite.basic
  • 103.16.vite.source
  • 103.16.vite.plugin
  • 103.16.vite.1
  • 103.16.vite.2
  • 103.17.polyfill
  • 104.1.binary
  • 104.2.binary
  • 105.skeleton
  • 106.1.react
  • 106.2.react_hooks
  • 106.3.react_router
  • 106.4.redux
  • 106.5.redux_middleware
  • 106.6.connected-react-router
  • 106.6.redux-first-history
  • 106.7.redux-saga
  • 106.8.dva
  • 106.9.umi
  • 106.10.ketang
  • 106.11.antdesign
  • 106.12.antpro
  • 106.13.router-6
  • 106.14.ssr
  • 106.15.nextjs
  • 106.16.1.cms
  • 106.16.2.cms
  • 106.16.3.cms
  • 106.16.4.cms
  • 106.16.mobx
  • 106.17.fomily
  • 107.fiber
  • 108.http
  • 109.1.webpack_usage
  • 109.2.webpack_source
  • 109.3.dll
  • 110.nest.js
  • 111.xstate
  • 112.Form
  • 113.redux-saga
  • 114.react+typescript
  • 115.immer
  • 116.pro5
  • 117.css-loader
  • 118.1.umi-core
  • 119.2.module-federation
  • 119.1.module-federation
  • 120.create-react-app
  • 121.react-scripts
  • 122.react-optimize
  • 123.jsx-runtime
  • 124.next.js
  • 125.1.linux
  • 125.2.linux-vi
  • 125.3.linux-user
  • 125.4.linux-auth
  • 125.5.linux-shell
  • 125.6.linux-install
  • 125.7.linux-system
  • 125.8.linux-service
  • 125.9.linux-network
  • 125.10.nginx
  • 125.11.docker
  • 125.12.ci
  • 125.13.k8s
  • 125.14.k8s
  • 125.15.k8s
  • 125.16.k8s
  • 126.11.react-1
  • 126.12.react-2
  • 126.12.react-3
  • 126.12.react-4
  • 126.12.react-5
  • 126.12.react-6
  • 126.12.react-7
  • 126.12.react-8
  • 127.frontend
  • 128.rollup
  • 129.px2rem-loader
  • 130.health
  • 131.hooks
  • 132.keepalive
  • 133.vue-cli
  • 134.react18
  • 134.2.react18
  • 134.3.react18
  • 135.function
  • 136.toolkit
  • 137.lerna
  • 138.create-vite
  • 139.cli
  • 140.antd
  • 141.react-dnd
  • 142.1.link
  • 143.1.gulp
  • 143.2.stream
  • 143.3.gulp
  • 144.1.closure
  • 144.2.v8
  • 144.3.gc
  • 145.react-router-v6
  • 146.browser
  • 147.lighthouse
  • 148.1.basic
  • 148.2.basic
  • 148.3.basic
  • 148.4.basic
  • 148.5.basic
  • 149.1.vite
  • 149.2.vite
  • 149.3.vite
  • 149.4.vite
  • 150.react-window
  • 151.react-query
  • 152.useRequest
  • 153.transition
  • 154.emotion
  • 155.1.formily
  • 155.2.formily
  • 155.3.formily
  • 155.3.1.mobx.usage
  • 155.3.2.mobx.source
  • 156.vue-loader
  • 103.11.mf
  • 157.1.react18
  • 158.umi4
  • 159.rxjs
  • 159.rxjs2
  • 160.bff
  • 161.zustand
  • 162.vscode
  • 163.emp
  • 164.cors
  • 1. Redux中间件
  • 2. 日志中间件
  • 2. 实现logger中间件
    • 2.1 store\index.js
    • 2.2 applyMiddleware.js
    • 2.3 compose.js
  • 3. 级联中间件
    • 3.1 Counter.js
    • 3.2 store\index.js
    • 3.3 reducers\index.js
    • 3.4 actions\counter.js
    • 3.5 redux-logger.js
    • 3.6 redux-thunk.js
    • 3.7 redux-promise.js
  • 4. redux-persist
    • 4.1 src\index.js
    • 4.2 store\index.js
    • 4.3 redux-persist\index.js
    • 4.4 persistReducer.js
    • 4.5 persistStore.js
    • 4.6 storage.js
    • 4.7 react.js
  • 5. redux-actions
    • 5.1 单个action
      • 5.1.1 actions\counter.js
      • 5.1.2 reducers\counter.js
    • 5.2 多个action
      • 5.2.1 actions\counter.js
      • 5.2.2 reducers\counter.js
  • 6. reselect
    • 6.1 基本用法
    • 6.2 案例
      • 6.2.1 src\index.js
      • 6.2.2 Counter1.js
      • 6.2.3 Counter2.js
      • 6.2.4 src\store\index.js
      • 6.2.5 reducers\index.js
      • 6.2.6 reducers\counter1.js
      • 6.2.7 reducers\counter2.js
      • 6.2.8 counter1.js
      • 6.2.9 actions\counter2.js
  • 7.undo
  • 附录

1. Redux中间件 #

reduxmiddleware

2. 日志中间件 #

  • 我们改写了,dispatch方法实现了在更改状态时打印前后的状态
  • 但是这种方案并不好。所以我们可以采用中间的方式
let store = createStore(reducer);
let dispatch = store.dispatch;
store.dispatch = function (action) {
  console.log(store.getState().number);
  dispatch(action);
  console.log(store.getState().number)
};
export default store;

2. 实现logger中间件 #

  • 中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能

2.1 store\index.js #

src\store\index.js

import { createStore,applyMiddleware } from '../redux';
import reducer from './reducers';
let logger = store => dispatch => action=>{
  console.log(store.getState().number);
  dispatch(action);
  console.log(store.getState().number)
};
export default applyMiddleware(logger)(createStore)(reducer);

2.2 applyMiddleware.js #

src\redux\applyMiddleware.js

  • applyMiddleware
import compose from './compose'
export default function applyMiddleware(...middlewares) {
 return createStore=>(...args)=>{
     const store = createStore(...args);
     let dispatch = ()=>{
         throw new Error('不允许派发正在构建中的中间件!');
     }
     const middlewareAPI= {
         getState:store.getState,
         dispatch:(...args)=>dispatch(...args)
     }
     const chain = middlewares.map(middleware=>middleware(middlewareAPI));
     dispatch = compose(...chain)(store.dispatch);
     return {
         ...store,
         dispatch
     }
 };
}

2.3 compose.js #

src\redux\compose.js

  • compose
function add1(str){
    return '1'+str;
}
function add2(str){
    return '2'+str;
}
function add3(str){
    return '3'+str;
}

function compose(...funcs){
    return funcs.reduce((a,b)=>(...args)=>a(b(...args)));
}

let result = compose(add3,add2,add1)('zfpx');
console.log(result);
export default function compose(...funcs) {
    if (funcs.length === 0) {
      return arg => arg
    }

    if (funcs.length === 1) {
      return funcs[0]
    }

    return funcs.reduce((a, b) => (...args) => a(b(...args)))
  }

3. 级联中间件 #

redux-middleware

3.1 Counter.js #

src\components\Counter.js

import React, { Component } from 'react';
import actions from '../store/actions/counter';
import {connect} from '../react-redux'
class Counter extends Component {
    render() {
        return (
            <div>
                <p>{this.props.number}</p>
                <button onClick={this.props.increment}>+</button>
                <button onClick={this.props.incrementAsync}>异步+1</button>
                <button onClick={this.props.incrementPromise}>promise异步+1</button>
            </div>
        )
    }
}

let mapStateToProps = state=>state;
export default connect(
    mapStateToProps,
    actions
)(Counter)

3.2 store\index.js #

src\store\index.js

import { createStore,applyMiddleware } from '../redux';
import reducer from './reducers';
import logger from '../redux-logger';
import thunk from '../redux-thunk';
import promise from '../redux-promise';
export default applyMiddleware(thunk,promise,logger)(createStore)(reducer);

3.3 reducers\index.js #

src\store\reducers\index.js

import counter from './counter';
export default counter;

3.4 actions\counter.js #

src\store\actions\counter.js

import * as types from '../action-types';
export default {
    increment(){
        return {type:types.INCREMENT};
    },
    decrement(){
        return {type:types.DECREMENT};
    },
    incrementAsync(){
        return function(dispatch){
            setTimeout(()=>{
                dispatch({type:types.INCREMENT});
            },1000);
        }
    },
    incrementPromise(){
        return {
            type:types.INCREMENT,
            payload:new Promise((resolve,reject)=>{
                let result = Math.random();
                if(result>.5){
                    resolve(result);
                }else{
                    reject(result);
                }
            },1000)
        }
    }
}

3.5 redux-logger.js #

src\redux-logger.js redux-logger.js

export default  store => dispatch => action=>{
    console.log(store.getState().number);
    dispatch(action);
    console.log(store.getState().number)
};

3.6 redux-thunk.js #

src\redux-thunk.js redux-thunk

function createThunkMiddleware(extraArgument) {
    return ({dispatch,getState}) => next => action => {
        if (typeof action == 'function') {
            return action(dispatch, getState, extraArgument);
        }
        return next(action);
    }
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;

3.7 redux-promise.js #

src\redux-promise.js redux-promise

function isPromise(obj) {
    return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
}
export default function promiseMiddleware({ dispatch }) {
    return next => action => {
        return isPromise(action.payload)
            ? action.payload
                .then(result => dispatch({ ...action, payload: result }))
                .catch(error => {
                    dispatch({ ...action, payload: error, error: true });
                    return Promise.reject(error);
                })
            : next(action);
    };
}

4. redux-persist #

4.1 src\index.js #

import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import Counter from './components/Counter';
import {Provider} from './react-redux';
+import {store,persistor} from './store';
+import { PersistGate } from './redux-persist/integration/react'

ReactDOM.render(<Provider store={store}>
+  <PersistGate persistor={persistor}>
     <Counter/>
+  </PersistGate>
</Provider>,document.getElementById('root'));

4.2 store\index.js #

src\store\index.js

import {createStore} from '../redux';
import reducer from './reducers';
import {applyMiddleware} from '../redux';
import logger from '../redux-logger';
import thunk from '../redux-thunk';
import promise from '../redux-promise';
+import { persistStore, persistReducer } from '../redux-persist'
+import storage from '../redux-persist/lib/storage'
+const persistConfig = {
+    key: 'root',
+    storage,
+}
+const persistedReducer = persistReducer(persistConfig, reducer);
+const store = applyMiddleware(thunk,promise,logger)(createStore)(persistedReducer);
+let persistor = persistStore(store)
+export {persistor,store};

4.3 redux-persist\index.js #

src\redux-persist\index.js

import persistReducer from './persistReducer';
import persistStore from './persistStore';

export {
    persistReducer,
    persistStore
}

4.4 persistReducer.js #

src\redux-persist\persistReducer.js

export default function (persistConfig, reducer) {
    let isInited = false;
    return (state, action) => {
        switch (action.type) {
            case 'PERSIST_INIT':
                isInited = true;
                let value = persistConfig.storage.getItem('persist:'+ persistConfig.key);
                state = value ? JSON.parse(value) : undefined;
                return reducer(state, action);
            default:
                if (isInited) {
                    state = reducer(state, action);
                    persistConfig.storage.setItem('persist:'+ persistConfig.key, JSON.stringify(state));
                    return state;
                }
                return reducer(state, action);
        }

    }
}

4.5 persistStore.js #

src\redux-persist\persistStore.js

export default function (store) {
    let persistor = {
        ...store,
        initState() {
            persistor.dispatch({
                type: 'PERSIST_INIT',
            })
        }
    };
    return persistor;
}

4.6 storage.js #

src\redux-persist\lib\storage.js

let storage = {
    setItem(key,val) {
        localStorage.setItem(key,val);
    },
    getItem(key) {
        return localStorage.getItem(key);
    }
}
export default storage;

4.7 react.js #

src\redux-persist\integration\react.js

import React, { Component } from 'react';

class PersistGate extends Component {
    componentDidMount() {
        this.props.persistor.initState();
    }
    render() {
        return this.props.children;
    }
}

export {PersistGate}

5. redux-actions #

  • redux-actions是一个实用的库,让编写redux状态管理变得简单起来。redux-action产生的动作是FSA标准的

5.1 单个action #

5.1.1 actions\counter.js #

src\store\actions\counter.js

import * as types from '../action-types';
//import { createAction } from 'redux-actions';
function createAction(type,payloadCreator){
  return function actionCreator(...args){
      return {type,payload:payloadCreator(...args)};
  }
}
const add = createAction(types.ADD,(payload)=>payload*2);
const minus = createAction(types.MINUS,(payload)=>payload*2);
export default {
    add,
    minus
}

5.1.2 reducers\counter.js #

src\store\reducers\counter.js

import *  as types from '../action-types';
//import {handleAction} from 'redux-actions';
import actions from '../actions/counter';
function handleAction(type,reducer ,defaultState){
    return function(state=defaultState,action){
        if(action.type === type){
            return reducer(state,action);
        }
        return state;
    } 
}
const initialState = {number:0};
const reducer = handleAction(types.ADD,(state,action)=>{
  return {
      ...state,number:state.number+action.payload
  }
},initialState);
export default reducer;

5.2 多个action #

5.2.1 actions\counter.js #

actions\counter.js

import * as types from '../action-types';
//import { createAction,createActions } from 'redux-actions';
export default createActions({
    [types.ADD]:(payload)=>payload*2,
    [types.MINUS]:(payload)=>payload*2
});
function createActions(actions){
    let newActions = {};
    for(let type in actions){
       newActions[type]= function(...args){
           return {type,payload:actions[type](...args)}
       }
    }
    return newActions;
}

5.2.2 reducers\counter.js #

reducers\counter.js

import *  as types from '../action-types';
//import {handleAction,handleActions } from 'redux-actions';
import actions from '../actions/counter';
const initialState = {number:0};
function handleActions(reducers,initialState){
   return function(state=initialState,action){
        let types = Object.keys(reducers);
        for(let i=0;i<types.length;i++){
            let type = types[i];
            if(type === action.type){
                return reducers[type](state,action);
            }
        }
        return state;
    } 
}
export default handleActions({
    [types.ADD]:(state,action)=>{
        return {
            ...state,number:state.number+action.payload
        }
    },
    [types.MINUS]:(state,action)=>{
        return {
            ...state,number:state.number-action.payload
        }
    }
},initialState);

6. reselect #

  • 使用Redux管理React应用状态时,mapStateToProps方法作为从Redux Store上获取数据过程中的重要一环,它一定不能有性能缺陷,它本身是一个函数,通过计算返回一个对象,这个计算过程通常是基于Redux Store状态树进行的,而很明显的Redux状态树越复杂,这个计算过程可能就越耗时,我们应该要能够尽可能减少这个计算过程,比如重复在相同状态下渲染组件,多次的计算过程显然是多余的,我们是否可以缓存该结果呢?这个问题的解决者就是reselect,它可以提高应用获取数据的性能
  • reselect的原理是,只要相关状态不变,即直接使用上一次的缓存结果

6.1 基本用法 #

  • reselect通过创建选择器(selectors),该函数接受一个state参数,然后返回我们需要在mapStateToProps方法内返回对象的某一个数据项,一个选择器的处理可以分为两个步骤
    • 接受state参数,根据我们提供的映射函数数组分别进行计算,如果返回结果和上次第一步的计算结果一致,说明命中缓存,则不进行第二步计算,直接返回上次第二步的计算结果,否则继续第二步计算。第一步的结果比较,通常仅仅是===相等性检查,性能是足够的
    • 根据第一步返回的结果,计算并返回最终结果
  • 需要注意的是,传入createSelector的映射函数返回的状态应该是不可变的,因为默认缓存命中检测函数使用引用检查,如果使用JavaScript对象,仅改变该对象的某一属性,引用检测是无法检测到属性变更的,这将导致组件无法响应更新
//import { createSelector } from 'reselect'
function createSelector(selector,reducer){
  let lastState;
  let value;
  return function(state){
    let newState = selector(state);
    if(lastState !== newState){
      value = reducer(newState);
      lastState = newState;
    }
    return value;
  }
}
const counterSelector = state => state.counter;

const getCounterSelector = createSelector(
  counterSelector,
  counter => {
    console.log('重新计算number')
    return counter.number;
  }
)


let initialState = {
  counter: {
    number:0
  }
}

console.log(getCounterSelector(initialState));
console.log(getCounterSelector(initialState));
+console.log(getCounterSelector(initialState));
+initialState.counter.number+=1;
+console.log(getCounterSelector(initialState));
+ console.log(getCounterSelector(initialState));
+ initialState.counter={number:1}
+ console.log(getCounterSelector(initialState));
+const immutable = require("immutable");
+let initialState = immutable.Map({counter: {number:0}})
+console.log(getCounterSelector(initialState.toJS()));
+initialState = initialState.setIn(['counter','number'],1);
+console.log(getCounterSelector(initialState.toJS()));

6.2 案例 #

6.2.1 src\index.js #

src\index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Counter1 from './components/Counter1';
import Counter2 from './components/Counter2';
import {Provider} from 'react-redux';
import store from './store';
ReactDOM.render(
<Provider store={store}>
  <><Counter1/><Counter2/></>
</Provider>,document.getElementById('root'));

6.2.2 Counter1.js #

src\components\Counter1.js

import React from 'react';
import {connect} from 'react-redux';
import { createSelector } from 'reselect'
import actions from '../store/actions/counter1';
class Counter extends React.Component{
    render(){
        return (
            <div>
                <p>{this.props.number}</p>
                <button onClick={this.props.add}>+</button>
                <button onClick={this.props.minus}>-</button>
            </div>
        )
    }
}

const getCounterSelector = state => state.get('counter1');

const counterSelector = createSelector(
  getCounterSelector,
  counter1 =>{
      console.log('重新计算counter1',counter1);
      return  counter1;
  }
)
export default connect(
    state=>counterSelector(state),
    actions
)(Counter)

6.2.3 Counter2.js #

src\components\Counter2.js

import React from 'react';
import {connect} from 'react-redux';
import { createSelector } from 'reselect'
import actions from '../store/actions/counter2';
class Counter extends React.Component{
    render(){
        return (
            <div>
                <p>{this.props.number}</p>
                <button onClick={()=>this.props.add(5)}>+</button>
                <button onClick={()=>this.props.minus(5)}>-</button>
            </div>
        )
    }
}

const getCounterSelector = state => state.get('counter2');

const counterSelector = createSelector(
  getCounterSelector,
  counter2 =>{
      console.log('重新计算counter2',counter2)
      return  counter2;
  }
)
export default connect(
    state=>counterSelector(state),
    actions
)(Counter)

6.2.4 src\store\index.js #

src\store\index.js

import {createStore,applyMiddleware} from 'redux';
import reducer from './reducers';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import promise from 'redux-promise';
let store = applyMiddleware(promise,thunk,logger)(createStore)(reducer);
export default store;

6.2.5 reducers\index.js #

src\store\reducers\index.js

//import {combineReducers} from 'redux';
import {combineReducers} from 'redux-immutable';
import counter1 from './counter1';
import counter2 from './counter2';
export default combineReducers({
    counter1,
    counter2
});

6.2.6 reducers\counter1.js #

src\store\reducers\counter1.js

import * as types from '../action-types';
import actions from '../actions/counter';
const initialState = {number:0};

export default function(state=initialState,action){
  switch(action.type){
      case types.ADD1:
        return {number:state.number+1};
      case types.MINUS1:
        return {number:state.number-1}; 
      default:  
        return state;   
  }
};

6.2.7 reducers\counter2.js #

src\store\reducers\counter2.js

import *  as types from '../action-types';
import actions from '../actions/counter';
const initialState = {number:0};

export default function(state=initialState,action){
  switch(action.type){
      case types.ADD2:
        return {number:state.number+1};
      case types.MINUS2:
        return {number:state.number-1}; 
      default:  
        return state;      
  }
};

6.2.8 counter1.js #

src\store\actions\counter1.js

import * as types from '../action-types';
export default {
    add(){
        return {type:types.ADD1}
    },
    minus(){
         return {type:types.MINUS1}
    }
}

6.2.9 actions\counter2.js #

src\store\actions\counter2.js

import * as types from '../action-types';
export default {
    add(){
        return {type:types.ADD2}
    },
    minus(){
         return {type:types.MINUS2}
    }
}

7.undo #

  • simple undo/redo functionality for redux state containers
  • redux-undo
  • 官网
import React, { Component, lazy, Suspense } from "react";
import ReactDOM from "react-dom";
import PropTypes from 'prop-types';
import {createStore} from 'redux';
//import undoable from 'redux-undo';
const INCREMENT='INCREMENT';
const DECREMENT = 'DECREMENT';
const UNDO_COUNTER = 'UNDO_COUNTER';
const REDO_COUNTER = 'REDO_COUNTER';
function reducer(state=0,action){
    switch(action.type){
        case INCREMENT:
            return state+1;
        case DECREMENT:
            return state-1;
        default:
            return state;
    }
}
function undoable(reducer,config){
    const {undoType="@@redux-unto/UNDO",redoType="@@redux-unto/REDO"}= config;
    const initialState = {
        past:[],
        futer:[],
        present:reducer(undefined,{})
    }
    return function(state=initialState,action){
        const {past,present,future} = state;
        switch(action.type){
            case undoType:
                const previous = past[past.length-1];
                const newPast = past.slice(0,past.length-1);
                return {
                    past:newPast,
                    present:previous,
                    future:[present,...future]
                }
            break;
            case redoType:
                const next = future[0];
                const newFuture = future.slice(1);
                return {
                    past:[...past,present],
                    present:next,
                    future:newFuture
                }
            break;
            default:
              const newPresent = reducer(present,action);
              return {
                  past:[...past,present],
                  present:newPresent,
                  future:[]
              }
        }
    }
}
let undoableReducer  = undoable(reducer,{
    undoType:UNDO_COUNTER,
    redoType:REDO_COUNTER
});
let store=createStore(undoableReducer);
class Counter extends Component{
    constructor(props) {
        super(props);
        this.state={value:store.getState()};
    }
    componentDidMount() {
        this.unsubscribe=store.subscribe(()=>this.setState({value:store.getState()}));
    }
    componentWillUnmount() {
        this.unsubscribe();
    }
    undo(){
      store.dispatch({type:UNDO_COUNTER});
    }
    redo(){
     store.dispatch({type:REDO_COUNTER});
    }
    add = ()=>{
        store.dispatch({type:INCREMENT});
    }
    render() {
        const {value,onInrement,onDecrement}=this.props;
        //{"past":[],"present":0,"future":[],"history":{"past":[],"present":0,"future":[]}}
        console.log(JSON.stringify(this.state.value));
        return (
            <div>
                <p>{this.state.value.present}</p>
                <button onClick={this.add}>+</button>
                <button onClick={()=>store.dispatch({type:DECREMENT})}>-</button>
                <button onClick={this.undo}>undo</button>
                <button onClick={this.redo}>redo</button>
            </div>
        )
    }
}
ReactDOM.render(<Counter/>, document.querySelector("#root"));

附录 #

  • redux
  • redux-logger
  • redux-promise
  • redux-thunk
  • redux-persist
  • redux-immutable
  • immutable-js
  • reselect

访问验证

请输入访问令牌

Token不正确,请重新输入