如果你不知道是否需要 Redux,那就是不需要它
只有遇到 React 实在解决不了的问题,你才需要 Redux
Store: 保存数据的地方,整个应用只能有一个 Store。
Redux 提供 createStore 函数来生成 Store
import { createStore } from 'redux'
const store = createStore(fn)
// createStore 函数接受另一个函数作为参数,返回新生成的 Store 对象
Store 对象包含所有数据,如果想得到某个时点的数据,就要对 Store 生成快照,这种时点的数据集合叫做 State
当前时刻的 State 可以通过 store.getState() 得到
import { createStore } from 'redux'
const store = createStore(fn)
const state = store.getState()
Redux 规定,一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然
State 的变化,会导致 View 的变化。但是用户接触不到 State,可以接触到 View,所以 State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了
Action 是一个对象。其中的 type 属性是必须的,表示 Action 的名称,其他属性自由设置
const action = {
type: 'ADD_TODO',
payload: 'learn redux'
}
定义一个函数来生成 Action,这个函数就叫 Action Creator
const ADD_TODO = '添加 TODO'
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
const action = addTodo('learn redux')
store.dispatch() 是 View 发出 Action 的唯一方法
store.dispatch 接受一个 Action 对象作为参数,将它发送出去
Store 收到 Action 以后,必须给出一个新的 State, 这样 View 才会发生变化,这种 State 的计算过程就叫做 Reducer
Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State
const reducer = function (state, action ) {
return newState
}
Reducer 函数不用手动调用,store.dispatch 方法会自动触发 Reducer 的自动执行。为此,Store 需要知道 Reducer 函数,做法就是在生成 Store 的时候,将 Reducer 传入 createStore 方法
import { createStore } from 'redux'
const store = createStore(reducer)
Reducer 函数最重要的特征: Reducer 是一个纯函数
// State 是一个对象
function reducer(state, action) {
return Object.assign({}, state, { thingToChange })
// 或者
return { ...state, ...newState }
}
// State 是一个数组
function reducer(state, action) {
return [...state, newItem]
}
Store 允许使用 store.subscribe 方法设置监听函数,一旦 State 发生变化,就自动执行这个函数
import { createStore } from 'redux'
const store = createStore(reducer)
store.subscribe(listener)
把 View 的更新函数(组件的render、setState)放入 listener ,就会实现 View 的自动渲染
store.subscribe 方法返回一个函数,调用这个函数就可以解除监听
let unsubscribe = store.subscribe(() => {
console.log(store.getState())
})
createStore 方法还可以接受第二个参数,表示 State 的最初状态。这通常是服务器给出的
let store = createStore(todoApp, window.STATE_FROM_SERVER)
window.STATE_FROM_SERVER: 就是整个应用的状态初始值。注意,如果提供了这个参数,它会覆盖 Reducer 函数的默认初始值
createStore 的简单实现
const createStore = (reducer) => {
let state
let listeners = []
const getState = () => state
const dispatch = (action) => {
state = reducer(state, action)
listeners.forEach(listener => listener())
}
const subscribe = (listener) => {
listeners.push(listener)
return () => {
listeners = listeners.filter(l => l !== listener)
}
}
dispatch({})
return { getState, dispatch, subscribe }
}
Redux 提供了一个方法:combineReducers, 用于 Reducer 的拆分
import { combineReducers } from 'redux'
const chatReducer = combineReducer({
a: chatLog,
b: stateMessage,
c: userName
})
export default todoApp
combineReducer 的简单实现
const combineReducers = reducers => {
return (state = {}, action) => {
return Object.keys(reducers).reducer(
(nextState, key) => {
nextState[key] = reducers[key](state[key], action)
return nextState
}
)
}
}
你可以把所有子 Reducer 放在一个文件里,然后统一引入
import { combineReducers } from 'redux'
import * as reducers from './reducers'
const reducer = combineReducers(reducers)
store.dispatch(action)
let nextState = todoApp(previousState, action)
State 一旦有变化,Store 就会调用监听函数
// 设置监听对象
store.subscribe(listener)
listener 可以通过 store.getState() 得到当前状态。如果使用的是 React,这时可以触发重新渲染 View
function listener () {
let newState = store.getState()
component.setState(newState)
}