rudux
redux
运行流程图:
简单概述:click -> store.dispatch(action) -> reduer -> newState -> viewUpdate
react-readux 中 通过 connect 链接组件和 redux , this.props.dispatch() 调用
后面将会讲到…
redux
依赖包也是十分的简洁
先来个demo
1 | const redux = require('redux') |
- 用户发出
action
【store.dispatch(action)
】 Store
自动调用Reducer
, 返回新的state
【let nextState = getUser(previousState, action)
】State
一旦有变化,Store
就会调用监听函数 【store.subscribe(listener)
】
运行过程如下:
store
Store
就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store
常用方法:
- store.dispatch() :分发 action 较为常用
- store.subscribe() : state 发生变化后立即执行
- store.getState() : 获取 store 中存着的 state
createStore
createStore 如其名,创建 store
下面是该方法的部分源码:
1 | /** |
preloadedState
: 初始化的initialState
,第二个参数不是Object
,而是Function
,createStore
会认为你忽略了preloadedState
而传入了一个enhancer
createStore
会返回enhancer(createStore)(reducer, preloadedState)
的调用结果,这是常见高阶函数的调用方式。在这个调用中enhancer
接受createStore
作为参数,对createStore
的能力进行增强,并返回增强后的createStore
dispatch(action)
diapatch
是 store 对象的方法,主要用来分发 action
,
redux 规定 action 一定要包含一个 type 属性,且 type 属性也要唯一
dispatch 是 store 非常核心的一个方法,也是我们在应用中最常使用的方法,下面是 dispatch 的源码 :
1 | function dispatch(action) { |
reducer && store.replaceReducer
Redux 中负责响应 action 并修改数据的角色就是reducer
,reducer
的本质实际上是一个函数
replaceReducer:
1 | /** |
replaceReducer 使用场景:
- 当你的程序要进行代码分割的时候
- 当你要动态的加载不同的 reducer 的时候
- 当你要实现一个实时 reloading 机制的时候
中间件 middleware
以上介绍了 redux 的实现流的过程,应用场景无非于
button – click –> disptch
– action –> reducer
– newState –> view
但是这种实现方式是基于同步的方式的,日常开发中当然少不了 http 这些异步请求,这种情况下必须等到服务器数据返回后才重新渲染 view, 显然某些时候回阻塞页面的展示。
举例来说,要添加日志功能,把 Action
和 State
打印出来,可以对 store.dispatch 进行如下改造。
1 | let next = store.dispatch |
上面代码中,对 store.dispatch 进行了重定义,在发送 Action 前后添加了打印功能。这就是中间件的雏形。
中间件就是一个函数,对 store.dispatch 方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。
applyMiddleware
Redux 提供了applyMiddleware
来装载middleware
:
它是 Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行。下面是它的源码。
1 | /** |
所有中间件被放进了一个数组 chain,然后嵌套执行,最后执行 store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到getState
和dispatch
这两个方法
compose
实际上是函数式编程中的组合,接收多个函数体并且将其组合成一个新的函数,例如compose
后 [fn1, fn2…] 依次从右到左嵌套执行函数 而compose
用于applyMiddleware
也是为了组合中间件
dispatch = compose(…chain)(store.dispatch)
==>
dispatch=fn1(fn2(fn3(store.dispatch)))
1 | /** |
redux-thunk
上面的中间件的介绍可以知道
redux 通过 applyMiddleware
来装载中间件,通过 compose 方法可以组合函数
异步的问题可以通过 redux-thunk
解决,用法也不难 react 组件中使用相关如下:
1 | // 配置 redux 加上这个... |
处理异步的还有很多插件 如 redux-soga 等,楼主并未实践过,所以不做延伸…
react-redux
下面是在 react 中使用的代码的雏形:
1 | import { createStore } from 'redux' |
mapStateToProps
- 用于建立组件跟 store 的 state 的映射关系作为一个函数,它可以传入两个参数,结果一定要返回一个 object
- 传入
mapStateToProps
之后,会订阅 store 的状态改变,在每次 store 的 state 发生变化的时候,都会被调用 - 如果写了第二个参数 props,那么当 props 发生变化的时候,mapStateToProps 也会被调用
mapDispatchToProps
mapDispatchToProps
用于建立组件跟 store.dispatch 的映射关系- 可以是一个 object,也可以传入函数
- 如果
mapDispatchToProps
是一个函数,它可以传入 dispatch,props,定义 UI 组件如何发出 action,实际上就是要调用 dispatch 这个方法
1 | import { connect } from 'react-redux' |
模块化配置
下面的配置仅供参考。实现的功能:
- 整合
action
、types
、reducer
到一个文件 - 根据开发/生成环境配置不同的
redux
中间件(开发环境配置dev-tools
) - 支持装饰器模式
redux
热加载配置(这里面顺便将react
热加载配置也加上了)
注意:项目基于 create-react-app
eject
后的配置改造实现的。下面用了别名 @ ,需要改下 webpack
的配置,如果你配置不成功。详情可以看我的 github
上面有源码. 链接入口
安装
1 | npm install redux react-redux redux-thunk --save |
相关文件夹如图:
models/demo.js
demo 模块。
1 | // types |
models/index.js
模块的导出口。
1 | import { combineReducers } from 'redux' |
redux/index.js
redux
仓库的总出口
1 | import thunk from 'redux-thunk' |
src/index.js
react 项目的入口配置。
1 | import React from 'react' |
App.jsx
1 | import React, { Component, Fragment } from 'react' |
.babelrc
配置 babel 装饰器模式
1 | { |
vscode 装饰器模式如果有报警的话,可以根目录下新建 jsconfig.json
1 | { |
参考
- 阮一峰 redux 入门教程
- 配置文件可以看我的 github : react-demo