Redux(一)-- 基礎(chǔ)概念

搞事情,搞事情,搞事情,又換技術(shù)棧了,學(xué)過的Vue沒雞兒用了。那就介紹介紹React全家桶中蛋疼的Redux。
Redux我就不多說了,因為以前看過Vuex,以為會上手簡單點,嗯....確實簡單點,但是還是很難學(xué)啊。
Redux的核心概念只有三個:Action,Reducer,Store。

Action

Action 是把數(shù)據(jù)從應(yīng)用傳到 store 的有效載荷。說白了就是你要告訴store要有事情發(fā)生了,順帶帶點東西過去。

// action.js
const ADD_TODO = "ADD_TODO"
store.dispatch({
  type: ADD_TODO,
  text: 'this is my first redux app'
})

上面代碼中的就表明action的本質(zhì)是一個對象。action 內(nèi)必須使用一個字符串類型的 type 字段來表示將要執(zhí)行的動作。就是一定要明確知道是干嘛去的。其他的字段就是按照需要定義攜帶的載荷,自行定義即可。
但是官方還是建議我們不要傳遞過大的數(shù)據(jù)量,盡量保持action的簡潔。

Action創(chuàng)建函數(shù)

就是把上面的對象通過函數(shù)返回,復(fù)用代碼。

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}
store.dispatch(addTodo("this is my first redux app"))

這里基本上是Action的主要東西。是不是很簡單???但是實際使用中我們很少直接去dispatch一個Action,多數(shù)情況下你會使用 react-redux 提供的 connect() 幫助器來調(diào)用。這個這里暫時不展開,后面會說。同時這里講的Action是同步的Action,異步的Action會在后面講解。

Reducer

上面說了,Action是告訴store要有事情發(fā)生了,但是還沒發(fā)生,具體的事情發(fā)生過程,也就是reducer操作改變state的過程。
Reducer是一個函數(shù),并且是一個純函數(shù),接收兩個參數(shù):舊的state和Action,返回新的state。聽起來也很簡單。但是寫reducer的時候有幾個注意點:

  • 不要修改傳入?yún)?shù)
  • 不要執(zhí)行有副作用的操作,如 API 請求和路由跳轉(zhuǎn)
  • 不要調(diào)用非純函數(shù),如 Date.now() 或 Math.random()
    因為上面這些操作會導(dǎo)致一些不可控制的狀態(tài)。
    純函數(shù)就是:只要傳入?yún)?shù)相同,返回計算得到的下一個 state 就一定相同。沒有特殊情況、沒有副作用,沒有 API 請求、沒有變量修改,單純執(zhí)行計算。
// reducer.js
// 這里就還是以官方的todolist為例子,這里故意采用不簡化的方式寫,后面優(yōu)化,一步步來
// redux 會在初始的時候調(diào)用一次 reducer (這時參數(shù) state 為 undefined), 可以借用這個機會返回應(yīng)用初始狀態(tài)數(shù)據(jù),或者直接用es6的寫法
const initialState = {
    todos: []
}
const todoApp = (state, action) => {
  if(typeof state === 'undefined'){
      state = initialState
  }
  ...
}
const todoApp = (state = initialState, action) => {
    switch (action.type) {
        case 'ADD_TODO':
            return Object.assign({}, state, {
                todos: [
                    ...state.todos,
                    {
                        id: action.id,
                        text: action.text,
                        completed: false
                    }
                ]
            })
        default: 
            return state
    }
}
//這里完成后的reducer最終是以以下的方式存在頂層的Store中
<頂層的唯一>store = {
    ...
    todoApp: {
        todos: []
    }
    ...
}

但是這里只有一個Action代碼已經(jīng)看起來不是很順眼了,如果Action多了看上去更加復(fù)雜,那我們就拆分一下

// reducer.js
import todos from 'todos.js'
const todoApp = (state = initialState, action) => {
    switch (action.type) {
        case 'ADD_TODO':
            return Object.assign({}, state, {
                todos: todos(state.todos, action)
            })
        default: 
            return state
    }
}
// todos.js
export default (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    default:
      return state
  }
}

這樣看來,其實程序中操作state中相同數(shù)據(jù)的reducer都可以進行合成,只管理自己對應(yīng)的那份數(shù)據(jù)就好了。
那對應(yīng)的reducer會變成下面這樣

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

簡潔明了,而visibilityFilter和todos則是額外提出來的方法而已。Redux本身也提供了這樣的方法combineReducers,下面的寫法和上面的寫法是完全等價的。

import { combineReducers } from 'redux';
const todoApp = combineReducers({
  visibilityFilter,
  todos
})
export default todoApp;

Store

Store就是存放應(yīng)用數(shù)據(jù)的地方,Store 有以下職責(zé):

  • 維持應(yīng)用的 state;
  • 提供 getState() 方法獲取 state;
  • 提供 dispatch(action) 方法更新 state;
  • 通過 subscribe(listener) 注冊監(jiān)聽器;
  • 通過 subscribe(listener) 返回的函數(shù)注銷監(jiān)聽器。
    需要注意的是一個應(yīng)用有且只有一個Store,就算需要拆分數(shù)據(jù)的邏輯時,也應(yīng)該用reducer的組合,而不是創(chuàng)建多個Store。
// 就像todolist例子中使用的一樣
import { combineReducers } from 'redux'
const todoApp = combineReducers({
  visibilityFilter,
  todos
})
const store = createStore(todoApp)

createStore() 的第二個參數(shù)是可選的, 用于設(shè)置 state 初始狀態(tài)。這對開發(fā)同構(gòu)應(yīng)用時非常有用,服務(wù)器端 redux 應(yīng)用的 state 結(jié)構(gòu)可以與客戶端保持一致, 那么客戶端可以將從網(wǎng)絡(luò)接收到的服務(wù)端 state 直接用于本地數(shù)據(jù)初始化。

let store = createStore(todoApp, window.STATE_FROM_SERVER)

至此,redux的基礎(chǔ)概念就完了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容