亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Redux 莞式教程 之 簡(jiǎn)明篇

notebin / 703人閱讀

摘要:只要一個(gè)有,那無論用什么設(shè)備訪問,都會(huì)得到這個(gè)還原也是相當(dāng)簡(jiǎn)單把數(shù)據(jù)庫(kù)備份導(dǎo)入到另一臺(tái)機(jī)器,部署同樣的運(yùn)行環(huán)境與代碼。純粹只是一個(gè)狀態(tài)管理庫(kù),幾乎可以搭配任何框架使用上述例子連都沒用哦親下一章進(jìn)階教程

Redux 簡(jiǎn)明教程

原文鏈接(保持更新):https://github.com/kenberkele...

寫在前面

本教程深入淺出,配套 簡(jiǎn)明教程、進(jìn)階教程(源碼精讀)以及文檔注釋豐滿的 Demo 等一條龍服務(wù)

§ 為什么要用 Redux

當(dāng)然還有 Flux、Reflux、Mobx 等狀態(tài)管理庫(kù)可供選擇

拋開需求講實(shí)用性都是耍流氓,因此下面由我扮演您那可親可愛的產(chǎn)品經(jīng)理

⊙ 需求 1:在控制臺(tái)上記錄用戶的每個(gè)動(dòng)作

不知道您是否有后端的開發(fā)經(jīng)驗(yàn),后端一般會(huì)有記錄訪問日志的中間件
例如,在 Express 中實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Logger 如下:

var loggerMiddleware = function(req, res, next) {
  console.log("[Logger]", req.method, req.originalUrl)
  next()
}
...
app.use(loggerMiddleware)

每次訪問的時(shí)候,都會(huì)在控制臺(tái)中留下類似下面的日志便于追蹤調(diào)試:

[Logger] GET  /
[Logger] POST /login
[Logger] GET  /user?uid=10086
...

如果我們把場(chǎng)景轉(zhuǎn)移到前端,請(qǐng)問該如何實(shí)現(xiàn)用戶的動(dòng)作跟蹤記錄?
我們可能會(huì)這樣寫:

/** jQuery **/
$("#loginBtn").on("click", function(e) {
  console.log("[Logger] 用戶登錄")
  ...
})
$("#logoutBtn").on("click", function() {
  console.log("[Logger] 用戶退出登錄")
  ...
})

/** MVC / MVVM 框架(這里以純 Vue 舉例) **/
methods: {
  handleLogin () {
    console.log("[Logger] 用戶登錄")
    ...
  },
  handleLogout () {
    console.log("[Logger] 用戶退出登錄")
    ...
  }
}

上述 jQuery 與 MV* 的寫法并沒有本質(zhì)上的區(qū)別
記錄用戶行為代碼的侵入性極強(qiáng),可維護(hù)性與擴(kuò)展性堪憂

⊙ 需求 2:在上述需求的基礎(chǔ)上,記錄用戶的操作時(shí)間

哼!最討厭就是改需求了,這種簡(jiǎn)單的需求難道不是應(yīng)該一開始就想好的嗎?
呵呵,如果每位產(chǎn)品經(jīng)理都能一開始就把需求完善好,我們就不用加班了好伐

顯然地,前端的童鞋又得一個(gè)一個(gè)去改(當(dāng)然 編輯器 / IDE 都支持全局替換):

/** jQuery **/
$("#loginBtn").on("click", function(e) {
  console.log("[Logger] 用戶登錄", new Date())
  ...
})
$("#logoutBtn").on("click", function() {
  console.log("[Logger] 用戶退出登錄", new Date())
  ...
})

/** MVC / MVVM 框架(這里以 Vue 舉例) **/
methods: {
  handleLogin () {
    console.log("[Logger] 用戶登錄", new Date())
    ...
  },
  handleLogout () {
    console.log("[Logger] 用戶退出登錄", new Date())
    ...
  }
}

而后端的童鞋只需要稍微修改一下原來的中間件即可:

var loggerMiddleware = function(req, res, next) {
  console.log("[Logger]", new Date(), req.method, req.originalUrl)
  next()
}
...
app.use(loggerMiddleware)
⊙ 需求 3:正式上線的時(shí)候,把控制臺(tái)中有關(guān) Logger 的輸出全部去掉

難道您以為有了 UglifyJS,配置一個(gè) drop_console: true 就好了嗎?圖樣圖森破,拿衣服!
請(qǐng)看清楚了,僅僅是去掉有關(guān) Logger 的 console.log,其他的要保留哦親~~~
于是前端的童鞋又不得不乖乖地一個(gè)一個(gè)注釋掉(當(dāng)然也可以設(shè)置一個(gè)環(huán)境變量判斷是否輸出,甚至可以重寫 console.log

而我們后端的童鞋呢?只需要注釋掉一行代碼即可:// app.use(loggerMiddleware),真可謂是不費(fèi)吹灰之力

⊙ 需求 4:正式上線后,自動(dòng)收集 bug,并還原出當(dāng)時(shí)的場(chǎng)景

收集用戶報(bào)錯(cuò)還是比較簡(jiǎn)單的,利用 window.error 事件,然后根據(jù) Source Map 定位到源碼(但一般查不出什么)

但要完全還原出當(dāng)時(shí)的使用場(chǎng)景,幾乎是不可能的。因?yàn)槟恢肋@個(gè)報(bào)錯(cuò),用戶是怎么一步一步操作得來的
就算知道用戶是如何操作得來的,但在您的電腦上,測(cè)試永遠(yuǎn)都是通過的(不是我寫的程序有問題,是用戶用的方式有問題)

相對(duì)地,后端的報(bào)錯(cuò)的收集、定位以及還原卻是相當(dāng)簡(jiǎn)單。只要一個(gè) API 有 bug,那無論用什么設(shè)備訪問,都會(huì)得到這個(gè) bug
還原 bug 也是相當(dāng)簡(jiǎn)單:把數(shù)據(jù)庫(kù)備份導(dǎo)入到另一臺(tái)機(jī)器,部署同樣的運(yùn)行環(huán)境與代碼。如無意外,bug 肯定可以完美重現(xiàn)

在這個(gè)問題上拿后端跟前端對(duì)比,確實(shí)有失公允。但為了鼓吹 Redux 的優(yōu)越,只能勉為其難了

實(shí)際上 jQuery / MV* 中也能實(shí)現(xiàn)用戶動(dòng)作的跟蹤,用一個(gè)數(shù)組往里面 push 用戶動(dòng)作即可
但這樣操作的意義不大,因?yàn)閮H僅只有動(dòng)作,無法反映動(dòng)作前后,應(yīng)用狀態(tài)的變動(dòng)情況

※ 小結(jié)

為何前后端對(duì)于這類需求的處理竟然大相徑庭?后端為何可以如此優(yōu)雅?
原因在于,后端具有統(tǒng)一的入口統(tǒng)一的狀態(tài)管理(數(shù)據(jù)庫(kù)),因此可以引入中間件機(jī)制統(tǒng)一實(shí)現(xiàn)某些功能

多年來,前端工程師忍辱負(fù)重,操著賣白粉的心,賺著買白菜的錢,一直處于程序員鄙視鏈的底層
于是有大牛就把后端 MVC 的開發(fā)思維搬到前端,將應(yīng)用中所有的動(dòng)作與狀態(tài)都統(tǒng)一管理,讓一切有據(jù)可循

使用 Redux,借助 Redux DevTools 可以實(shí)現(xiàn)出“華麗如時(shí)光旅行一般的調(diào)試效果”
實(shí)際上就是開發(fā)調(diào)試過程中可以撤銷與重做,并且支持應(yīng)用狀態(tài)的導(dǎo)入和導(dǎo)出(就像是數(shù)據(jù)庫(kù)的備份)
而且,由于可以使用日志完整記錄下每個(gè)動(dòng)作,因此做到像 Git 般,隨時(shí)隨地恢復(fù)到之前的狀態(tài)

由于可以導(dǎo)出和導(dǎo)入應(yīng)用的狀態(tài)(包括路由狀態(tài)),因此還可以實(shí)現(xiàn)前后端同構(gòu)(服務(wù)端渲染)
當(dāng)然,既然有了動(dòng)作日志以及動(dòng)作前后的狀態(tài)備份,那么還原用戶報(bào)錯(cuò)場(chǎng)景還會(huì)是一個(gè)難題嗎?

§ Store

首先要區(qū)分 storestate

state 是應(yīng)用的狀態(tài),一般本質(zhì)上是一個(gè)普通對(duì)象
例如,我們有一個(gè) Web APP,包含 計(jì)數(shù)器 和 待辦事項(xiàng) 兩大功能
那么我們可以為該應(yīng)用設(shè)計(jì)出對(duì)應(yīng)的存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)(應(yīng)用初始狀態(tài)):

/** 應(yīng)用初始 state,本代碼塊記為 code-1 **/
{
  counter: 0,
  todos: []
}

store 是應(yīng)用狀態(tài) state 的管理者,包含下列四個(gè)函數(shù):

getState() # 獲取整個(gè) state

dispatch(action) # ※ 觸發(fā) state 改變的【唯一途徑】※

subscribe(listener) # 您可以理解成是 DOM 中的 addEventListener

replaceReducer(nextReducer) # 一般在 Webpack Code-Splitting 按需加載的時(shí)候用

二者的關(guān)系是:state = store.getState()

Redux 規(guī)定,一個(gè)應(yīng)用只應(yīng)有一個(gè)單一的 store,其管理著唯一的應(yīng)用狀態(tài) state
Redux 還規(guī)定,不能直接修改應(yīng)用的狀態(tài) state,也就是說,下面的行為是不允許的:

var state = store.getState()
state.counter = state.counter + 1 // 禁止在業(yè)務(wù)邏輯中直接修改 state

若要改變 state,必須 dispatch 一個(gè) action,這是修改應(yīng)用狀態(tài)的不二法門

現(xiàn)在您只需要記住 action 只是一個(gè)包含 type 屬性的普通對(duì)象即可
例如 { type: "INCREMENT" }

上面提到,state 是通過 store.getState() 獲取,那么 store 又是怎么來的呢?
想生成一個(gè) store,我們需要調(diào)用 Redux 的 createStore

import { createStore } from "redux"
...
const store = createStore(reducer, initialState) // store 是靠傳入 reducer 生成的哦!

現(xiàn)在您只需要記住 reducer 是一個(gè) 函數(shù),負(fù)責(zé)更新并返回一個(gè)新的 state
initialState 主要用于前后端同構(gòu)的數(shù)據(jù)同步(詳情請(qǐng)關(guān)注 React 服務(wù)端渲染)

§ Action

上面提到,action(動(dòng)作)實(shí)質(zhì)上是包含 type 屬性的普通對(duì)象,這個(gè) type 是我們實(shí)現(xiàn)用戶行為追蹤的關(guān)鍵
例如,增加一個(gè)待辦事項(xiàng) 的 action 可能是像下面一樣:

/** 本代碼塊記為 code-2 **/
{
  type: "ADD_TODO",
  payload: {
    id: 1,
    content: "待辦事項(xiàng)1",
    completed: false
  }
}

當(dāng)然,action 的形式是多種多樣的,唯一的約束僅僅就是包含一個(gè) type 屬性罷了
也就是說,下面這些 action 都是合法的:

/** 如下都是合法的,但就是不夠規(guī)范 **/
{
  type: "ADD_TODO",
  id: 1,
  content: "待辦事項(xiàng)1",
  completed: false
}

{
  type: "ADD_TODO",
  abcdefg: {
    id: 1,
    content: "待辦事項(xiàng)1",
    completed: false
  }
}

雖說沒有約束,但最好還是遵循規(guī)范

如果需要新增一個(gè)代辦事項(xiàng),實(shí)際上就是將 code-2 中的 payload “寫入”state.todos 數(shù)組中(如何“寫入”?在此留個(gè)懸念):

/** 本代碼塊記為 code-3 **/
{
  counter: 0,
  todos: [{
    id: 1,
    content: "待辦事項(xiàng)1",
    completed: false
  }]
}

刨根問底,action 是誰生成的呢?

⊙ Action Creator

Action Creator 可以是同步的,也可以是異步的

顧名思義,Action Creator 是 action 的創(chuàng)造者,本質(zhì)上就是一個(gè)函數(shù),返回值是一個(gè) action對(duì)象
例如下面就是一個(gè) “新增一個(gè)待辦事項(xiàng)” 的 Action Creator:

/** 本代碼塊記為 code-4 **/
var id = 1
function addTodo(content) {
  return {
    type: "ADD_TODO",
    payload: {
      id: id++,
      content: content, // 待辦事項(xiàng)內(nèi)容
      completed: false  // 是否完成的標(biāo)識(shí)
    }
  }
}

將該函數(shù)應(yīng)用到一個(gè)表單(假設(shè) store 為全局變量,并引入了 jQuery ):

<--! 本代碼塊記為 code-5 -->



在輸入框中輸入 “待辦事項(xiàng)2” 后,點(diǎn)擊一下提交按鈕,我們的 state 就變成了:

/** 本代碼塊記為 code-6 **/
{
  counter: 0,
  todos: [{
    id: 1,
    content: "待辦事項(xiàng)1",
    completed: false
  }, {
    id: 2,
    content: "待辦事項(xiàng)2",
    completed: false
  }]
}

通俗點(diǎn)講,Action Creator 用于綁定到用戶的操作(點(diǎn)擊按鈕等),其返回值 action 用于之后的 dispatch(action)

剛剛提到過,action 明明就沒有強(qiáng)制的規(guī)范,為什么 store.dispatch(action) 之后,
Redux 會(huì)明確知道是提取 action.payload,并且是對(duì)應(yīng)寫入到 state.todos 數(shù)組中?
又是誰負(fù)責(zé)“寫入”的呢?懸念即將揭曉...

§ Reducer

Reducer 必須是同步的純函數(shù)

用戶每次 dispatch(action) 后,都會(huì)觸發(fā) reducer 的執(zhí)行
reducer 的實(shí)質(zhì)是一個(gè)函數(shù),根據(jù) action.type更新 state 并返回 nextState
最后會(huì)用 reducer 的返回值 nextState 完全替換掉原來的 state

注意:上面的這個(gè) “更新” 并不是指 reducer 可以直接對(duì) state 進(jìn)行修改
Redux 規(guī)定,須先復(fù)制一份 state,在副本 nextState 上進(jìn)行修改操作
例如,可以使用 lodash 的 deepClone,也可以使用 Object.assign / map / filter/ ... 等返回副本的函數(shù)

在上面 Action Creator 中提到的 待辦事項(xiàng)的 reducer 大概是長(zhǎng)這個(gè)樣子 (為了容易理解,在此不使用 ES6 / Immutable.js):

/** 本代碼塊記為 code-7 **/
var initState = {
  counter: 0,
  todos: []
}

function reducer(state, action) {
  // ※ 應(yīng)用的初始狀態(tài)是在第一次執(zhí)行 reducer 時(shí)設(shè)置的(除非是服務(wù)端渲染) ※
  if (!state) state = initState
  
  switch (action.type) {
    case "ADD_TODO":
      var nextState = _.deepClone(state) // 用到了 lodash 的深克隆
      nextState.todos.push(action.payload) 
      return nextState

    default:
    // 由于 nextState 會(huì)把原 state 整個(gè)替換掉
    // 若無修改,必須返回原 state(否則就是 undefined)
      return state
  }
}

通俗點(diǎn)講,就是 reducer 返回啥,state 就被替換成啥

§ 總結(jié)

store 由 Redux 的 createStore(reducer) 生成

state 通過 store.getState() 獲取,本質(zhì)上一般是一個(gè)存儲(chǔ)著整個(gè)應(yīng)用狀態(tài)的對(duì)象

action 本質(zhì)上是一個(gè)包含 type 屬性的普通對(duì)象,由 Action Creator (函數(shù)) 產(chǎn)生

改變 state 必須 dispatch 一個(gè) action

reducer 本質(zhì)上是根據(jù) action.type 來更新 state 并返回 nextState函數(shù)

reducer 必須返回值,否則 nextState 即為 undefined

實(shí)際上,state 就是所有 reducer 返回值的匯總(本教程只有一個(gè) reducer,主要是應(yīng)用場(chǎng)景比較簡(jiǎn)單)

Action Creator => action => store.dispatch(action) => reducer(state, action) => 原 state state = nextState

⊙ Redux 與傳統(tǒng)后端 MVC 的對(duì)照
Redux 傳統(tǒng)后端 MVC
store 數(shù)據(jù)庫(kù)實(shí)例
state 數(shù)據(jù)庫(kù)中存儲(chǔ)的數(shù)據(jù)
dispatch(action) 用戶發(fā)起請(qǐng)求
action: { type, payload } type 表示請(qǐng)求的 URL,payload 表示請(qǐng)求的數(shù)據(jù)
reducer 路由 + 控制器(handler)
reducer 中的 switch-case 分支 路由,根據(jù) action.type 路由到對(duì)應(yīng)的控制器
reducer 內(nèi)部對(duì) state 的處理 控制器對(duì)數(shù)據(jù)庫(kù)進(jìn)行增刪改操作
reducer 返回 nextState 將修改后的記錄寫回?cái)?shù)據(jù)庫(kù)
§ 最簡(jiǎn)單的例子 ( 在線演示 )



  




由上可知,Redux 并不一定要搭配 React 使用。Redux 純粹只是一個(gè)狀態(tài)管理庫(kù),幾乎可以搭配任何框架使用
(上述例子連 jQuery 都沒用哦親)

§ 下一章:Redux 進(jìn)階教程

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/80157.html

相關(guān)文章

  • Redux 莞式教程 進(jìn)階

    摘要:進(jìn)階教程原文保持更新寫在前面相信您已經(jīng)看過簡(jiǎn)明教程,本教程是簡(jiǎn)明教程的實(shí)戰(zhàn)化版本,伴隨源碼分析用的是編寫,看到有疑惑的地方的,可以復(fù)制粘貼到這里在線編譯總覽在的源碼目錄,我們可以看到如下文件結(jié)構(gòu)打醬油的,負(fù)責(zé)在控制臺(tái)顯示警告信息入口文件除去 Redux 進(jìn)階教程 原文(保持更新):https://github.com/kenberkele... 寫在前面 相信您已經(jīng)看過 Redux ...

    岳光 評(píng)論0 收藏0
  • Redux 進(jìn)階 - react 全家桶學(xué)習(xí)筆記(二)

    摘要:在函數(shù)式編程中,異步操作修改全局變量等與函數(shù)外部環(huán)境發(fā)生的交互叫做副作用通常認(rèn)為這些操作是邪惡骯臟的,并且也是導(dǎo)致的源頭。 注:這篇是17年1月的文章,搬運(yùn)自本人 blog... https://github.com/BuptStEve/... 零、前言 在上一篇中介紹了 Redux 的各項(xiàng)基礎(chǔ) api。接著一步一步地介紹如何與 React 進(jìn)行結(jié)合,并從引入過程中遇到的各個(gè)痛點(diǎn)引出 ...

    Godtoy 評(píng)論0 收藏0
  • 前端每周清單半年盤點(diǎn) React 與 ReactNative

    摘要:前端每周清單半年盤點(diǎn)之與篇前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。與求同存異近日,宣布將的構(gòu)建工具由遷移到,引發(fā)了很多開發(fā)者的討論。 前端每周清單半年盤點(diǎn)之 React 與 ReactNative 篇 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為...

    Barry_Ng 評(píng)論0 收藏0
  • 前端速查表大全,分享一些技術(shù)和工具的簡(jiǎn)明教程

    摘要:這個(gè)速查表主要是分享互聯(lián)網(wǎng)上一些比較常用的工具和技術(shù)常用內(nèi)容,如編輯器的快捷鍵的命令行的選擇器的屬性等,這個(gè)列表簡(jiǎn)單收集了常用的工具,可以收藏用于平時(shí)的備忘錄,需要用到的時(shí)候可以及時(shí)查閱。 這個(gè)速查表主要是分享互聯(lián)網(wǎng)上一些比較常用的工具和技術(shù)常用內(nèi)容,如編輯器的快捷鍵、git的命令行、jQuery的API選擇器、CSS的flexbox屬性等,這個(gè)列表簡(jiǎn)單收集了常用的工具,可以收藏用于平...

    xiaochao 評(píng)論0 收藏0
  • 前端速查表大全,分享一些技術(shù)和工具的簡(jiǎn)明教程

    摘要:這個(gè)速查表主要是分享互聯(lián)網(wǎng)上一些比較常用的工具和技術(shù)常用內(nèi)容,如編輯器的快捷鍵的命令行的選擇器的屬性等,這個(gè)列表簡(jiǎn)單收集了常用的工具,可以收藏用于平時(shí)的備忘錄,需要用到的時(shí)候可以及時(shí)查閱。 這個(gè)速查表主要是分享互聯(lián)網(wǎng)上一些比較常用的工具和技術(shù)常用內(nèi)容,如編輯器的快捷鍵、git的命令行、jQuery的API選擇器、CSS的flexbox屬性等,這個(gè)列表簡(jiǎn)單收集了常用的工具,可以收藏用于平...

    avwu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<