關於 Redux 的介紹能夠參考: Redux 中文文檔。Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。一般在 React 中使用 Redux 時,還使用到React-Redux、Redux-Saga。javascript
Redux做爲全局的狀態管理器,整個應用的 state 被儲存在一棵 object tree 中,而且這個 object tree 只存在於惟一一個 store 中。惟一改變 state 的方法就是觸發 action,action 會經過執行 reducer 來改變 state 的值, state 的改變會引發視圖層的改變,即 Component 的改變。Redux 的工做流以下圖所示:java
在實際開發過程當中,除 action 和 reducer 以外,還會用到一些中間件 middleware ,中間件本質就是在 dispatch 更改 reducer 以前作一些操做,這裏涉及到 Redux 的一個重要 api:applyMiddleware ,在後續篇幅中會詳細介紹。在實際的業務開發中,將全部更新 state 的邏輯都放入到單個 reducer 函數中都將會讓程序變得不可維護,所以對 reducer 的拆分是頗有必要的,這裏也涉及到 Redux 的另一個重要 api:combineReducers ,關於這部分在後文也會詳細分析。若是加上這部分分析, Redux 的工做流就能夠用下圖更加詳細的說明。react
Redux 做爲全局的狀態管理器,自己與 React 沒有直接關係的。若是讓 Redux 的狀態可以在 React 的視圖組件中展現,而且在視圖組件能夠更改 Redux 的狀態,這就依賴於 React-Redux 。React-Redux 的核心是 Provider 組件 和 connect 方法 。git
Provider 的本質就是 React 的 context屬性 ,經過在將 Provider 組件包裹 組件,並傳入 Redux 的 store 屬性,這樣在 的後代組件中就能夠經過獲取到 store 中 state 的值。github
<Provider store={store}>
<App /> </Provider>,
複製代碼
connect 方法的做用從字面上能夠理解爲:將 Redux 中 store 和 視圖 View 關聯起來。connect 本質是一個高階函數。其中mapStateToProps能夠解釋爲:將 store 中的 state 的映射到 Component 中,完成 Model 層到 View 層的展現。mapDispatchToProps 能夠解釋爲:如何從 Component 中去更改 store 中的 state,完成從 View 層到 Model 層的改變。redux
connect(mapStateToProps, mapDispatchToProps)(MyComponent)
複製代碼
固然在 Redux 的 store 中的 state 發生變化,也會完成 Redux 的訂閱 subscribe 的執行,也包括 mapStateToProps、 mapDispatchToProps 等方法的從新執行 ,關於 react-redux 可後續篇幅專門分析。api
Redux-Saga 自己就是 Redux 的一箇中間件 middleware ,是爲了解決 Redux 的一些異步的處理, 是經過 ES6 的 Generator 去實現的,讓異步流程能夠經過同步的方式去實現。數組
瞭解了 Redux 的一些生態介紹以後,咱們有必要看看 Redux 是如何使用,只有在熟練使用的基礎上,咱們才能更好的對源碼有清晰的認識。下邊截取了一些重要的代碼,完整代碼剋制 克隆。app
在項目的入口文件處,分別引用了 react-Redux 中的 Provider 組件;redux 中的 createStore 方法和 applyMiddleware 方法,項目的 reducer 定義在 reducer.js 頁面中。爲了後續源碼解讀中可以更好的闡述中間件部分,此處定義了兩個簡單的中間件 Logger 和 Test。中間件本質是一個高階函數,分別接受 store 、next、 action 參數,經過調用 applyMiddleware方法將中間件組合起來使用,這裏先給出結論,後續中間件的分析中會詳細說明:中間件的組合使用本質上就是改變 next 的值,其中 store 對應爲 Redux 的數據模型 store, action 本質上是 JavaScript 普通對象。咱們約定,action 內必須使用一個字符串類型的 type 字段來表示將要執行的動做。dom
//index.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from './redux';
import rootReducer from './reducers';
import App from './components/App';
// middleware
const Logger = (store) => (next) => (action) => {
console.info('logger start');
let result = next(action);
console.info('logger end');
};
const Test = (store) => (next) => (action) => {
console.info('test start');
let result = next(action);
console.info('test end');
};
let store = createStore(rootReducer, applyMiddleware(Logger, Test));
render(
<Provider store={store}> <App /> </Provider>,
document.getElementById('root')
);
複製代碼
createStore 方法的官方介紹以下,簡單來說:reducer 既能夠是單個 reducer 對象 也能夠是經過 combineReducers 組合的 reducer 對象。preloadedState 若是存在則表示 reducer 的初始值,若是 reducer 參數是經過 combineReducers 組合生成的,則 preloadedState 必須是一個對象,key 值必須與 combineReducers時的key值對應 (否則 redux 怎麼知道初始化那個 reducer )。enhancer 的官方解釋比較難懂,能夠簡單理解爲 enhancer 就是經過傳入中間件到 applyMiddleware 方法產生的結果。
createStore(reducer, [preloadedState], enhancer) 建立一個 Redux store 來以存放應用中全部的 state。 應用中應有且僅有一個 store。
參數
reducer (Function): 接收兩個參數,分別是當前的 state 樹和要處理的 action,返回新的 state 樹。
[preloadedState] (any): 初始時的 state。 在同構應用中,你能夠決定是否把服務端傳來的 state 水合(hydrate)後傳給它,或者從以前保存的用戶會話中恢復一個傳給它。若是你使用 combineReducers 建立 reducer,它必須是一個普通對象,與傳入的 keys 保持一樣的結構。不然,你能夠自由傳入任何 reducer 可理解的內容。
enhancer (Function): Store enhancer 是一個組合 store creator 的高階函數,返回一個新的強化過的 store creator。這與 middleware 類似,它也容許你經過複合函數改變 store 接口。
reducer 接收兩個參數,分別是當前的 state 樹和要處理的 action,返回新的 state 樹。以 實例中 todos 爲例,state 默認爲返回空數組 [] , 根據 action.type 的不一樣類型返回不一樣的值。在當期實例中,reducer 是經過 combineReducers 組合生成的, 在實際開發中全部 state 和 改變 state 的邏輯放在一個 reducer 中顯然是不合適,combineReducers 的意義就在對各個業務模塊的 reducer 進行組合,最後傳遞給 redux 的 createStore 方法,繼而生成一個的狀態數。
合併後的 reducer 能夠調用各個子 reducer,並把它們返回的結果合併成一個 state 對象。 由 combineReducers() 返回的 state 對象,會將傳入的每一個 reducer 返回的 state 按其傳遞給 combineReducers() 時對應的 key 進行命名。
官方文檔的解釋能夠簡單理解爲:combineReducers 會將各個 reducer 按照 key 值組合(當前實例是經過 ES6 語法簡寫),在你 dispatch(action) 時,也會根據你 key 值來改變 store 中 對應的 state 的值。
// rootReduce.js
import { combineReducers } from '../redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'
export default combineReducers({
todos,
visibilityFilter
})
//todos.js
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
]
case 'TOGGLE_TODO':
return state.map(
todo =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
)
default:
return state
}
}
複製代碼
此示例中經過 react-redux 將 redux 和 react 關聯起來,根據上文的介紹 react-redux 的 connect 方法經過 :
// Component
const TodoList = ({ todos, toggleTodo }) => (
<ul> {todos.map(todo => ( <Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} /> ))} </ul> ) const mapStateToProps = state => ({ todos: getVisibleTodos(state.todos, state.visibilityFilter) }) const mapDispatchToProps = dispatch => ({ toggleTodo: id => dispatch(toggleTodo(id)) }) export default connect( mapStateToProps, mapDispatchToProps )(TodoList) 複製代碼
以上demo實例基本上涵蓋了redux 的基本使用,並對於 react-redux 也有一些簡單的介紹,完整的理解上述demo的流程,對於後續詳細源碼分析大有益處。