Redux
是一款狀態管理庫,而且提供了react-redux
庫來與React
親密配合, 可是老是傻傻分不清楚這2者提供的API
和相應的關係。這篇文章就來理一理。react
Redux
的核心由三部分組成:Store
, Action
, Reducer
。redux
Store
: 是個對象,貫穿你整個應用的數據都應該存儲在這裏。Action
: 是個對象,必須包含type
這個屬性,reducer
將根據這個屬性值來對store
進行相應的處理。除此以外的屬性,就是進行這個操做須要的數據。Reducer
: 是個函數。接受兩個參數:要修改的數據(state) 和 action
對象。根據action.type
來決定採用的操做,對state
進行修改,最後返回新的state
。===== Store ===== { todos: [], visibilityFilter: 'SHOW_ALL' } ===== Action ===== { type: 'ADD_TODO', text: 'Build my first Redux app' } ===== Reducer ===== const todos = (state = [], action) => { switch (action.type) { case 'ADD_TODO': return [ ...state, { id: action.id, text: action.text, completed: false } ] default: return state } }
在上一部分,咱們提到了,咱們觸發action
→ reducer來處理
。這就是兩者之間的關係。那麼咱們怎麼觸發action
呢?Store
這個對象提供了dispatch方法
→ 觸發action
。dispatch
方法接受action
對象做爲參數。所以,咱們能夠了解三者之間的關係:app
`store` ➡️ `dispatch` ➡️ `action` ⬅️ `reducer`
咱們經過redux
提供的createStore
這個方法來建立一個Store
。它接受對store
進行處理的reducer
做爲參數。ide
Store
有三個方法:函數
getState
:用來獲取store
裏面存儲的數據。dispatch
: store
裏的數據不能直接修改,只能經過觸發action
來進行修改,這個方法就是用來觸發action
。subscibe
:訂閱store
改變時,要進行的操做。好比在react
中,當store
改變時,咱們須要調用render
方法對視圖進行更新。const store = createStore(reducer); store.getState(); // { todos: [], visibilityFilter: 'SHOW_ALL' } store.dispatch({ type: 'ADD_TODO', text: 'Build my first Redux app' }); store.subscibe(() => { console.log(store.getState()); });
咱們能夠將對store
的操做,寫在一個reducer
中,好比:工具
function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }) case ADD_TODO: case TOGGLE_TODO: return Object.assign({}, state, { todos: todos(state.todos, action) }) default: return state } }
能夠看到這個reducer
對store
的visibilityFilter
和todos
的兩部分數據進行了處理。隨着應用的複雜,若是咱們把對全部數據的處理,都寫在一個reducer
中,那麼它會變得很冗雜。若是咱們將對每一部分的數據的處理,寫在一個單獨的reducer
中,它接受該部分的數據做爲state
。那麼整個reducer
會變得整潔和清晰。ui
所以,redux
爲咱們提供了combineReducer
這個API
,幫助咱們分開書寫reducer
, 而且最終把這些reducer
給集合到一個根reducer
中。spa
// 對todos進行處理 function todos(state = [], action) { switch (action.type) { case ADD_TODO: return [ ...state, { text: action.text, completed: false } ] default: return state } } // 對 visibilityFilter 進行處理 function visibilityFilter(state = SHOW_ALL, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return action.filter default: return state } } // 生成 root reducer function todoApp(state = {}, action) { return { visibilityFilter: visibilityFilter(state.visibilityFilter, action), todos: todos(state.todos, action) } } // 建立store const store = createStore(todoApp)
上一部分咱們介紹了redux
的核心。能夠看到,redux
是獨立的應用狀態管理工具。它是能夠獨立於react
以外的。若是咱們須要在react
當中運用它,那麼咱們須要手動訂閱store
的狀態變化,來對咱們的react
組件進行更新。那麼react-reudx
這個工具,就幫咱們實現了這個功能,咱們只需對store
進行處理,react
組件就會有相應的變化。code
這個工具主要提供兩個API
:對象
connect
如今咱們有了store
,那麼咱們怎麼才能在咱們的組件中對它們進行操做呢?connect
就爲提供了這個功能。它接受mapStateToProps
, mapDispatchToProps
等做爲參數。好比在個人TodoList
這個組件中須要用到todos
這部分數據,那麼我完善mapStateToProps
這個函數,它接受store
中的state
做爲參數,返回一個對象,屬性就是state
中咱們須要的數據:
const mapStateToProps = state => { return { todos: state.todos } }
mapStateToProps
就將咱們的state
轉換爲了props
對象。
一樣的,咱們可能須要在組件中對state
進行處理。mapDispatchToProps
就是幫助咱們在組件中經過props
調用dispatch
來觸發action
的:
const mapDispatchToProps = dispatch => { return { onTodoClick: id => { dispatch(toggleTodo(id)) } } }
最後咱們調用connect
這個方法,將mapStateToProps
, mapDispatchToProps
生成的props
注入到須要使用它的組`中:
const VisibleTodoList = connect( mapStateToProps, mapDispatchToProps )(TodoList)
這樣,咱們在TodoList
這個組件中,就能直接經過props.todos
獲取到todos
中的數據, 經過props.onTodoClick
對todos
進行處理。
provider
上面咱們調用connect
時,在mapStateToProps
和 mapDispatchToProps
咱們分別用到了store
的state
和dispatch
。可是在組件中的store
是哪裏憑空冒出來的呢?
provider
就是來解決這個事的。Provider
使它的子孫在調用connect
方法時,都能獲取到store
。
const VisibleTodoList = connect( mapStateToProps, mapDispatchToProps )(TodoList) const App = () => ( <div> <AddTodo /> <VisibleTodoList /> <Footer /> </div> ) <Provider store={store}> <App /> </Provider>
這樣,Provider
的子孫組件都能在調用connect
時獲取到store
。
Redux: store
, action
, reducer
store
: getState
, dispatch
, subscribe
combineReducers
createStore
store
➡️ dispatch
➡️ action
⬅️ reducer
react-redux:
connect
: 將store
做爲props
注入Provider
: 使store
在子孫組件的connect
中可以獲取到。