Redux 關係圖解

Redux是一款狀態管理庫,而且提供了react-redux庫來與React親密配合, 可是老是傻傻分不清楚這2者提供的API和相應的關係。這篇文章就來理一理。react

關係圖

Redux

Redux 三大核心

Redux的核心由三部分組成:Store, Action, Reducerredux

  • 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
  }
}

Redux核心之間的關係

在上一部分,咱們提到了,咱們觸發actionreducer來處理。這就是兩者之間的關係。那麼咱們怎麼觸發action呢?Store這個對象提供了dispatch方法觸發actiondispatch方法接受action對象做爲參數。所以,咱們能夠了解三者之間的關係:app

`store`  ➡️  `dispatch`  ➡️   `action`  ⬅️  `reducer`

Store

咱們經過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());
});

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
  }
}

能夠看到這個reducerstorevisibilityFiltertodos的兩部分數據進行了處理。隨着應用的複雜,若是咱們把對全部數據的處理,都寫在一個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)

react-redux

上一部分咱們介紹了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這個方法,將mapStateToPropsmapDispatchToProps生成的props注入到須要使用它的組`中:

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

這樣,咱們在TodoList這個組件中,就能直接經過props.todos獲取到todos中的數據, 經過props.onTodoClicktodos進行處理。

provider

上面咱們調用connect時,在mapStateToPropsmapDispatchToProps咱們分別用到了storestatedispatch。可是在組件中的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中可以獲取到。
相關文章
相關標籤/搜索