redux有5个接口
createStore
combineReducers
bindActionCreators
applyMiddleware
compose
一. createStore
createStore函数有三个参数
reducer:reducer是一个函数,该函数会返回一个全新的state,而state则保存了所有的数据
preloadedState:初始state
enhancer:这个参数特别有意思,如果该enhancer参数存在的话,会将当前的createStore
函数作为参数传入enhancer函数,并且,enhancer执行之后得到一个新函数,该新函数其实
就是一个加强版的createStore函数,新的函数会把之前的reducer和preloadeState作为参数
传入并执行。这个enhancer参数为redux中间件提供了入口。
createStore 的函数的作用就是生成一个 store 对象,这个对象具有5个方法:
return {
dispatch, // 传入 action,调用 reducer 及触发 subscribe 绑定的监听函数
subscribe,
getState,
replaceReducer, // 用新的 reducer 代替当前的 reducer,使用不多
[$$observable]: observable
}
compose 函数则是 applyMiddleware 函数的核心,其会形成串联的函数调用关系,用于增强 dispatch 方法。
二. applyMiddleware
applyMiddleware方法主要是对redux的dispacth方法进行封装
而 applyMiddleware 函数的作用就是对 store.dispatch 方法进行增强和改造,使得在发出 Action 和执行 Reducer 之间添加其他功能。
单一的state是存储在store中,当要对state进行更新的时候,首先要发起一个action(通过dispatch函数),action的作用就是相当于一个消息通知,用来描述发生了什么(比如:增加一个Todo),然后reducer会根据action来进行对state更新,这样就可以根据新的state去渲染View。
当然上面仅仅是发生同步Action的情况下,如果是Action是异步的(例如从服务器获取数据),那么情况就有所不同了,必须要借助Redux的中间件Middleware。
根据官方的解释,Redux中间件在发起一个action至action到达reducer的之间,提供了一个第三方的扩展。本质上通过插件的形式,将原本的action->redux的流程改变为action->middleware1->middleware2-> ... ->reducer,通过改变数据流,从而实现例如异步Action、日志输入的功能。
使用方式
const store = applyMiddleware(...middlewares)(createStore)(reducer, initialState)
首先我们举例不使用中间件Middleware创建store:
import rootReducer from './reducers'
import {createStore} from 'redux'
let store = createStore(rootReducer);
那么使用中间件的情况下(以redux-logger举例),创建过程如下:
import rootReducer from './reducers'
import {createStore,applyMiddleware} from 'redux'
import createLogger from 'redux-logger'
const loggerMiddleware = createLogger();
let store = applyMiddleware(loggerMiddleware)(createStore)(rootReducer);
三. combineReducers
随着应用变得复杂,需要对 reducer 函数 进行拆分,拆分后的每一块独立负责管理 state 的一部分。
那么问题来了,这么拆分如何使用createStore去创建store呢,毕竟createStore只能传一个Reducer参数。而且createStore只能调用一次。
在redux中提供了一个combineReducers的方法,用来组合我们的Reducer。
const mainReducer = combineReducers({
homeReducer,
profileReducer
})
let store = createStore(mainReducer);
示例
reducers/todos.js
export default function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text])
default:
return state
}
}
reducers/counter.js
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
reducers/index.js
import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'
export default combineReducers({
todos,
counter
})
App.js
import { createStore } from 'redux'
import reducer from './reducers/index'
let store = createStore(reducer)
console.log(store.getState())
// {
// counter: 0,
// todos: []
// }
store.dispatch({
type: 'ADD_TODO',
text: 'Use Redux'
})
console.log(store.getState())
// {
// counter: 0,
// todos: [ 'Use Redux' ]
// }