Redux 是 JavaScript 状态容器,提供可预测化的状态管理
三大原则
单一数据源
整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中
State 是只读的
唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象
使用纯函数来执行修改
为了描述 action 如何改变 state tree ,你需要编写 reducers
Action
action的本质是javascript对象,action 内必须使用一个字符串类型的type字段来表示将要执行的动作
//action.js
//ADD_BOOK 新增book
export function addBook(data) {
return { type: 'ADD_BOOK', data }
}
//DEL_BOOK 删除book
export function delBook(id) {
return { type: 'DEL_BOOK', id }
}
Reducers
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store,reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。
//redecures
function books(state = [], action) {
switch (action.type) {
case 'ADD_BOOK':
return [
...state,
action.data
]
case 'DEL_BOOK':
return state.filter(v => v.id !== action.id)
default:
return state
}
}
function app(state = {}, action) {
return {
books: books(state.books, action)
}
}
export default app
Reducers合成
实际开发过程中,可能会有多个reducers函数,每个reducer 只负责管理全局 state 中它负责的一部分。每个 reducer 的 state 参数都不同,分别对应它管理的那部分 state 数据。
function app(state = {}, action) {
return {
books: books(state.book, action),
music: music(state.music, action),
...
...
...
}
}
combineReducers
redux提供combineReducers方法来实现app方法,减少样板代码
import { combineReducers } from 'redux'
const app = combineReducers({
books,
music
})
}
combineReducers方法实现
export default function(reducers){
const keys = Object.keys(reducers)
const newReducers = {}
keys.forEach(item => {
if(typeof reducers[item] === 'function'){
newReducers[item] = reducers[item]
}
})
return function(state = {}, action){
const keys = Object.keys(newReducers)
keys.forEach(item => {
//拿到旧的state
const oldState = state[item]
//执行reducers获取新的state
const data = newReducers[item](oldState, action)
state[item] = data
})
return state
}
}
Store
getState() 方法获取 state
dispatch(action) 方法更新 state
subscribe(listener) 注册监听器
subscribe(listener) 返回的函数注销监听器
import {createStore} from 'redux'
import {
addBook,
delBook
} from './actions'
import todoApp from './reducers'
const store = createStore(todoApp)
store.dispatch(addBook({
id: 'N0000001',
name: '西游记'
}))
setTimeout(() => {
store.dispatch(delBook('N0000001'))
}, 1000)
store.subscribe(() => {
console.log(store.getState())
})
createStore
创建一个 Redux store 来以存放应用中所有的 state。应用中应有且仅有一个 store。
export default function createStore(reducer, preloadedState, enhancer){
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
function subscribe(listener) {
if (isDispatching) {
throw new Error('isDispatching...')
}
let isSubscribed = true
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) {
throw new Error('isDispatching...')
}
isSubscribed = false
//移除监听
nextListeners.splice(nextListeners.indexOf(listener), 1)
}
}
function dispatch(action){
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
}
function getState() {
if (isDispatching) {
throw new Error('isDispatching...')
}
//返回新的状态树
return currentState
}
return{
getState,
dispatch,
subscribe
}
}