Redux
May 24, 2022
build your own redux
明确需求
以下是一段 redux 的简单使用例子
import { createStore } from 'redux'
const initState = {
name: 'hutchins',
age: 25
}
const reducer = (state = initState, action) => {
if (!state) {
return initState
}
if (action.type === 'UPDATE_NAME') {
return {
...state,
name: action.payload
}
} else if (action.type === 'UPDATE_AGE') {
return {
...state,
age: action.payload
}
} else {
return state
}
}
const store = createStore(reducer)
const actions = {
updateName: (name) =>
store.dispatch({
type: 'UPDATE_NAME',
payload: name
}),
updateAge: (age) =>
store.dispatch({
type: 'UPDATE_AGE',
payload: age
})
}
store.subscribe(() => {
console.info(store.getState())
})
actions.updateAge(20) // {name: "hutchins", age: 20}
actions.updateName('hengheng') // {name: "hengheng", age: 20}
通过上述例子,我们总结出,我们需要实现的方法只有一个,那就是 createStore,这个方法接受一个 reducer 方法作为参数,返回一个 store 对象,store 对象中包含 subscribe、dispatch、getState 方法。
interface Action<T = any> {
type: T
}
interface AnyAction extends Action {
// Allows any extra properties to be defined in an action.
[extraProps: string]: any
}
type Reducer<S = any, A extends Action = AnyAction> = (state: S, action: A) => S
type Store = {
getState: () => any
dispatch: (action: AnyAction) => void
subscribe: (listener: () => void) => { unsubscribe: () => void }
}
const createStore = (reducer: Reducer): Store
需求实现
export const createStore = (reducer: Reducer): Store => {
let state: any = null
let listeners: any[] = []
// 订阅
const subscribe = (listener: any) => {
listeners.push(listener)
return {
unsubscribe: () => {
listeners = listeners.filter((l) => l !== listener)
}
}
}
// 触发
const dispatch = (action: AnyAction) => {
state = reducer(state, action)
listeners.forEach((l) => l(state))
}
// 初始化 state
dispatch({ type: Symbol('redux init') })
const getState = () => state
return {
getState,
subscribe,
dispatch
}
}
可以看到,redux 就是一个非常经典的订阅发布模式,subscribe 订阅,dispatch 获得 action 的给 reducer 去更新 state 并通知所有订阅者