创建一个 React Store
来存储应用中所有的 State
,应用中应仅有一个 Store
。
DEMO
先从一个 Demo 来开始源码分析:
import { createStore } from 'redux'
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text])
default:
return state
}
}
let store = createStore(todos, ['Use Redux'])
store.dispatch({
type: 'ADD_TODO',
text: 'Read the docs'
})
console.log(store.getState())
上面的代码,我们就能得到state
为['Use Redux', 'Read the docs']
。
createStore 源码
方法:createStore(reducer, [preloadedState], [enhancer])
参数:
reducer
是一个函数,该函数接收两个参数:state
和action
,且返回一个新的state
preloadedState
初始时的state
enhancer
是一个组合式的store creator
的高阶函数,返回一个新的强化过的store creator
。于middleware
有些相似。
返回值: 一个新的state
对象。
export default function createStore(reducer, preloadedState, enhancer) {
// 有初始化函数state,且没有传第三参数,enhancer 即为 preloadedState
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
// 不是空,且不是一个函数,报错
throw new Error('Expected the enhancer to be a function.')
}
// 对enhancer进行createStore处理,把reduce传进去
return enhancer(createStore)(reducer, preloadedState)
}
// reducer必需是一个函数
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
function ensureCanMutateNextListeners() {
// 当这里指向同一个数组时,创建一个新的副本
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
// 返回当前的state
function getState() {
return currentState
}
// redux的订阅函数,订阅 dispatch
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
if (isDispatching) {
throw new Error('')
}
let isSubscribed = true
ensureCanMutateNextListeners() // 每次调用,确保nextListeners变量是新的副本
nextListeners.push(listener) // 存储订阅者
// 返回一个可以取消订阅的函数
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) {
throw new Error('')
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
currentListeners = null
}
}
// 派发函数,用于触发 reducer 修改 state
function dispatch(action) {
if (!isPlainObject(action)) { // action 必需是对象
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
if (typeof action.type === 'undefined') { // 必需有type字段
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
// 派发中不能再调用,想了一下,正常情况下不会走到这里,哪怕是多次调用也不会
// 可能存在的就是是 reducer 里面又调用了dispatch,这样会导致state不是最新的。
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
// 正在派发中。。。
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
// 派发结束,执行所有订阅者函数
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
// 如果你的应用实现了代码拆分,需要动态加载reducer,需要用到
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
dispatch({ type: ActionTypes.REPLACE })
}
// 该方法的作用是,订阅store的变化,适用于所有observable的类库。比如 RxJS。
function observable() {
const outerSubscribe = subscribe
return {
subscribe(observer) {
if (typeof observer !== 'object' || observer === null) {
throw new TypeError('Expected the observer to be an object.')
}
// // 用于给 subscribe 注册的函数,严格按照 Observable 的规范实现,observer 必须有一个 next 属性。
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
// $$observable 即为 Symbol.observable,也属于 Observable 的规范,返回自身。
[$$observable]() {
return this
}
}
}
// 初始化时执行一个 INIT 类型的action
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
总结
createStore
方法返回一个对象,里面包含了一些常用的 API
。
dispatch
派发任务subscribe
实现了观察者模式,每次dispatch
后都会遍历一遍currentListeners
getState
返回当前的state
replaceReducer
代码拆分时动态加载reducer