Redux和React-Redux使用關係
Redux
是一款狀態管理庫,並且提供了react-redux
庫來與React
親密配合, 但是總是傻傻分不清楚這2者提供的API
和相應的關係。這篇文章就來理一理。
Redux
Redux 三大核心
Redux
的核心由三部分組成:Store
, Action
, Reducer
。
Store
: 是個物件,貫穿你整個應用的資料都應該儲存在這裡。Action
: 是個物件,必須包含type
這個屬性,reducer
將根據這個屬性值來對store
進行相應的處理。除此之外的屬性,就是進行這個操作需要的資料。Reducer
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 } }
Redux核心之間的關係
在上一部分,我們提到了,我們觸發action
→ reducer來處理
。這就是二者之間的關係。那麼我們怎麼觸發action
呢?Store
這個物件提供了dispatch方法
→ 觸發action
。dispatch
方法接受action
物件作為引數。因此,我們可以瞭解三者之間的關係:
`store` ➡️ `dispatch` ➡️ `action` ⬅️ `reducer`
Store
我們通過redux
提供的createStore
這個方法來建立一個Store
。它接受對store
進行處理的reducer
作為引數。
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());
});
Reducer
我們可以將對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
會變得整潔和清晰。
因此,redux
為我們提供了combineReducer
這個API
,幫助我們分開書寫reducer
, 並且最終把這些reducer
給集合到一個根reducer
中。
// 對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)
react-redux
上一部分我們介紹了redux
的核心。可以看到,redux
是獨立的應用狀態管理工具。它是可以獨立於react
之外的。如果我們需要在react
當中運用它,那麼我們需要手動訂閱store
的狀態變化,來對我們的react
元件進行更新。那麼react-reudx
這個工具,就幫我們實現了這個功能,我們只需對store
進行處理,react
元件就會有相應的變化。
這個工具主要提供兩個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
中能夠獲取到。