Redux
介绍
Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理。就是一个函数式的状态管理器。 主要有以下几个特点:
- 单一数据源
- 状态不可变性
- 纯函数,没有副作用
- 单向数据流 (单一数据源以及单向数据流使其的数据具备可预测性)
简单使用
- 创建一个store
import {createStore} from 'redux'
const store = createStore(reducerName)
export default store
- 创建store的修改规则,也就是reducer
/**
state 需要管理的store
action 传递的数据
**/
const reducer = (state, action) => {
switch (action.type) {
case 'ADD':
state += 1
break;
case 'MIN':
state -= 1
break;
default:
return state;
}
// 最后记得返回
return state
}
- 使用 store
import store from './store'
// 记得订阅数据变化
componentDidMount () {
this.forceUpdate()
}
add = () => {
store.dispatch({type: 'ADD'})
}
min = () => {
store.dispatch({type: 'MIN'})
}
render () {
return (
<div> store.getState()</div>
<button onClick={this.add}>add</button>
<button onClick={this.min}>min</button>
)
}
常用Api
- createStore
- applyMiddleware
- combineReducers
原理
利用函数式编程做统一状态管理,实现单向数据流,使数据的流转变得可预测。
实现简单的redux
使用redux的两个关键Api就是:
- createStore
- applyMiddleware
在实现createStore一级applyMiddleware之前我们先来了解一下中间件。
中间件
Redux 的中间件提供的是位于 action 被发起之后,到达 reducer 之前的扩展点,换而言之,原本 view -> action -> reducer -> store 的数据流加上中间件后变成了 view -> action -> middleware -> reducer -> store ,在这一环节可以做一些"副作用"的操作,如 异步请求、打印日志等。
我们先看看如何使用:
// 使用
import {createStore,applyMiddleware} from 'redux'
const reducer = (state, action) => {
switch (action.type) {
case 'ADD':
state += 1
break;
case 'MIN':
state -= 1
break;
default:
return state;
}
// 最后记得返回
return state
}
// middles一些中间件
const middlewares = applyMiddleware(...middles)
//preloadedState 默认值
const store = createStore(reducer,preloadedState,middlwares)
export default store
中间件怎么写
import isPromsie from 'is-promise'
// 日志打印
function logger({getState,dispatch}) {
return next => action =>{
console.log('will dispatch', action)
// Call the next dispatch method in the middleware chain.
const returnValue = next(action)
// 打印修改之后的state值
console.log('state after dispatch', getState())
// This will likely be the action itself, unless
// a middleware further in chain changed it.
return returnValue
}
}
// 让dispatch支持promise
function supportPromise ((getState,dispatch)) {
return next => action => {
// 这里只需要检查一下action是否是promise即可,不是的话直接执行即可
return isPromsie(action)?action.then(dispatch):next(action)
}
}
createStore如何实现
先看createStore返回了什么内容
主要是以下几个方法
{
dispatch,
subscribe,
getState
}
实现自定义createStore
// reducer 修改规则
// preloadedState 默认值
// enhancer 存储增强器。您可以选择指定它来通过第三方功能(例如中间件、时间旅行、持久性等)增强 存储。Redux 附带的唯一存储增强器是。 [`applyMiddleware()`]
function createStore(reducer,preloadedState,enhancer) {
// 如果有增强器那就直接执行增强器
if (enhancer) {
// enhancer加强dispatch
return enhancer(createStore)(reducer);
}
let currentState;
let listeners = []
// 派发事件
const dispatch = (action) => {
currentState = reducer(currentState,action)
//然后通知所有事件
listeners.map(listener => listener())
}
// 监听事件
const subscribe = (listener) => {
let len = listeners.push(listener)
return () => {
const index = len - 1
listeners.splice(index,1)
}
}
// 返回当前store的store
const getState = () => {
return currentState
}
return {
dispatch,
subscribe,
getState
}
}
applyMiddleware如何实现
了解了中间件是怎么实现加上如何使用applyMiddleware应用中间件,那我们就知道applyMiddleware大概是需要什么参数以及返回什么了。
首先applyMiddleware组合了中间件之后返回增强器给到了createStore里面去使用能知道它返回的是一个接受next(createStore)参数的函数,该函数又是返回一个接受action得函数:“enhancer(createStore)(reducer)”,最后函数应该返回与createStore返回一样的结果,只是给dispatch包装了一些中间件的执行,变成了一个高级的dispatch。
所以applyMiddleware的基本结构就是
function applyMiddleware(...middlewares) {
return (createStore) => (reducer) => {
let store = createStore(resucer)
return {
...store
}
}
}
接下来就是对store的dispatch进行重新封装。从实现中间件的方法中可以知道,中间件默认是接受({getState, dispatch})参数的。所以我们先把dispatch包装起来
function applyMiddleware(...middlewares) {
return (createStore) => (reducer) => {
let store = createStore(resucer)
let midApi = {
getState: store.getState,
dispatch: (action,...args) => store.dispatch(action,...args)
}
// 遍历所有的中间件把midApi给进去每个中间件
let middlewareChain = middlewares.map(middleware => middleware(midApi))
// 得到的是中间件的执行函数数组
// [
// (next) => (action) => {
// }
//]
// 下一步就是在执行dispatch的时候把所有中间件都按照顺序执行一次,真正变成一个高级dispatch
//这里就利用到组合函数的概念,
// 这里最后还需要调用一次并给 store.dispatch是因为第一个调用的中间件函数需要接受一个next(也就是dispatch),而之后接受的都是上一个中间件函数执行返回的一个函数,也就是(action) => {}
// 所以 dispatch 也是接受 action的函数,因为中间件最后一个返回的函数是(action) => {}
let dispatch = compose(...middlewareChain)(store.dispatch)
return {
...store,
dispatch
}
}
}
// 组合执行就是按照顺序依次执行一些方法
// 利用reduce方法,把上一次执行的结果给到下一次执行
// 由于middleware每次执行都是返回一个接受 action的函数
// 所以在 middleware中的next就是上一次中间件待执行的函数
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)))
}
组合函数
再了解一下applyMiddleware里面使用到的compose函数(组合函数)。
将多个函数按照一定顺序组合起来,以便将一个函数的输出作为另一个函数的输入,这就是函数的组合。
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)))
}
例如:
function fn1(...args) {
console.log('fn1',...args)
return 1
}
function fn2(...args) {
console.log('fn2',...args)
return 2
}
function fn3(...args) {
console.log('fn3',...args)
return 3
}
compose(fn1,fn2,fn3)(0)
输出:=>
fn3 0
fn2 3
fn1 2
1