Redux學(xué)習(xí)

官方文檔

核心思路

將變化的動作和數(shù)據(jù)本身抽象并出來并分離開。提供統(tǒng)一的API發(fā)起變化和更新數(shù)據(jù)

Redux中組成部分

action + reducer + store

action

Action 是把數(shù)據(jù)從應(yīng)用(譯者注:這里之所以不叫 view 是因為這些數(shù)據(jù)有可能是服務(wù)器響應(yīng),用戶輸入或其它非 view 的數(shù)據(jù) )傳到 store 的有效載荷。它是 store 數(shù)據(jù)的唯一來源。
https://www.redux.org.cn/docs/basics/Actions.html

Reducer

Reducers 指定了應(yīng)用狀態(tài)的變化如何響應(yīng) actions 并發(fā)送到 store 的,記住 actions 只是描述了有事情發(fā)生了這一事實,并沒有描述應(yīng)用如何更新 state。

拆分reducer

拆分前:

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false
          }
        ]
      })
    case TOGGLE_TODO:
      return Object.assign({}, state, {
        todos: state.todos.map((todo, index) => {
          if (index === action.index) {
            return Object.assign({}, todo, {
              completed: !todo.completed
            })
          }
          return todo
        })
      })
    default:
      return state
  }
}

拆分后

function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}

使用combineReducers拆分reducer

import { combineReducers } from 'redux'
import {
  ADD_TODO,
  TOGGLE_TODO,
  SET_VISIBILITY_FILTER,
  VisibilityFilters
} from './actions'
const { SHOW_ALL } = VisibilityFilters

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp

Store

就是把它們聯(lián)系到一起的對象。Store 有以下職責(zé):

三大原則
1.單一數(shù)據(jù)源.整個應(yīng)用的 state 被儲存在一棵 object tree 中,并且這個 object tree 只存在于唯一一個 [store]
2.State 是只讀的.唯一改變 state 的方法就是觸發(fā) action,action 是一個用于描述已發(fā)生事件的普通對象
3.使用純函數(shù)來執(zhí)行修改.為了描述 action 如何改變 state tree ,你需要編寫 reducers

Redux和Flux的對比
不同于 Flux ,Redux 并沒有 dispatcher 的概念。原因是它依賴純函數(shù)來替代事件處理器。純函數(shù)構(gòu)建簡單,也不需額外的實體來管理它們。

數(shù)據(jù)流

嚴(yán)格的單向數(shù)據(jù)流是 Redux 架構(gòu)的設(shè)計核心。
1.調(diào)用 store.dispatch(action)
2.Redux store 調(diào)用傳入的 reducer 函數(shù)。
3.根 reducer 應(yīng)該把多個子 reducer 輸出合并成一個單一的 state 樹。
4.Redux store 保存了根 reducer 返回的完整 state 樹。

異步action

保持reducer的純凈,把異步邏輯放到action中

const fetchPosts = subreddit => dispatch => {
  dispatch(requestPosts(subreddit))
  return fetch(`https://www.reddit.com/r/${subreddit}.json`)
    .then(response => response.json())
    .then(json => dispatch(receivePosts(subreddit, json)))
}

middleware

middleware提供的是位于 action 被發(fā)起之后,到達 reducer 之前的擴展點。 你可以利用 Redux middleware 來進行日志記錄、創(chuàng)建崩潰報告、調(diào)用異步接口或者路由等等。
因為所有的操作都被統(tǒng)一收口再redux中,所以可以很方便簡潔地插入middleware
在reducer中插入middleware

const middleware = [ thunk ]
if (process.env.NODE_ENV !== 'production') {
  middleware.push(createLogger())
}

const store = createStore(
  reducer,
  applyMiddleware(...middleware)
)

日志記錄和上報

const logger = store => next => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}

const crashReporter = store => next => action => {
  try {
    return next(action)
  } catch (err) {
    console.error('Caught an exception!', err)
    Raven.captureException(err, {
      extra: {
        action,
        state: store.getState()
      }
    })
    throw err
  }
}

import { createStore, combineReducers, applyMiddleware } from 'redux'

let todoApp = combineReducers(reducers)
let store = createStore(
  todoApp,
  // applyMiddleware() 告訴 createStore() 如何處理中間件
  applyMiddleware(logger, crashReporter)
)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容