從零到一搭建 react 項(xiàng)目系列之(七)

上一篇介紹了 react-router,今天介紹 redux。

什么是 Redux?

現(xiàn)如今,我們的項(xiàng)目都是由一個(gè)一個(gè)的模塊組成的,組件化的思想更適合大且復(fù)雜的項(xiàng)目。

在此之前,React 并不適合寫大型應(yīng)用,因?yàn)樗?dāng)時(shí)還沒有很好地解決組件之間的通信問題。

為了解決這個(gè)問題,2014 年 Facebook 提出了 Flux 架構(gòu)的概念,引發(fā)了很多的實(shí)現(xiàn)。2015 年,Redux 出現(xiàn),將 Flux 與函數(shù)式編程結(jié)合在一起,很短時(shí)間內(nèi)就成為了最熱門的前端框架。

什么時(shí)候需要 Redux?

有人說過,挺有道理的哈。

如果你不知道是否需要 Redux,那就是不需要它。

在以下場(chǎng)景你可以考慮使用它:

  • 組件間需要共享狀態(tài)
  • 狀態(tài)需要在任何地方都能拿到
  • 一個(gè)組件需要改變另一個(gè)組件的狀態(tài)
  • 一個(gè)組件需要改變?nèi)譅顟B(tài)

*以上內(nèi)容引自阮一峰老師的博客,本教程是為了接入而接入,哈哈。

Redux 設(shè)計(jì)思想

  • Web 應(yīng)用是一個(gè)狀態(tài)機(jī),View 與 State 是一一對(duì)應(yīng)的。
  • 所有的狀態(tài),保存在一個(gè)對(duì)象里面。

基本概念和 API

先了解一下以下幾個(gè)概念吧

  • Store:保存數(shù)據(jù)的容器。由 Redux 提供的 createStore 函數(shù)來生成唯一的 Store 對(duì)象。

  • StateStore 對(duì)象包含的數(shù)據(jù)。當(dāng)前的狀態(tài),可通過 store.getState() 獲取。Redux 規(guī)定一個(gè) State 對(duì)應(yīng)一個(gè) View。

  • ActionView 發(fā)出的動(dòng)作(如用戶點(diǎn)擊鼠標(biāo)等行為)通知 State 要發(fā)生改變。Action 是改變 State 的唯一辦法。它是一個(gè)對(duì)象,其中 type 屬性是必須的,表示 Action 的名稱,其他屬性可以自由設(shè)置,其社區(qū)有一個(gè)規(guī)范可以參考。如 const action = { type: 'SOMETHING_TODO', payload: 'SOME DATA' }。

  • Action Creator:生成 Action 的函數(shù)。當(dāng)有若干 Action 時(shí),全部手寫可能略顯麻煩,可以定義一個(gè)函數(shù)來生成 Action,這種函數(shù)叫做 Action Creator。

  • store.dispatch():是 View 發(fā)出 Action 的唯一方式。

  • Reducer:當(dāng) Store 收到 Action 之后,必須返回一個(gè)新的 State,這樣 View 才會(huì)發(fā)生變化,這種 State的計(jì)算過程叫做 Reducer。它是一個(gè)純函數(shù)。

  • Pure Function:即純函數(shù),同樣的輸入,必定得到同樣的輸出,且沒有任何副作用

  • store.subscribe():監(jiān)聽 State 的變化,一旦 State 發(fā)生變化,就自動(dòng)執(zhí)行這個(gè)函數(shù)。它返回一個(gè)函數(shù),執(zhí)行該返回函數(shù)就解除監(jiān)聽。

實(shí)現(xiàn)最簡(jiǎn)單的 Store 案例

先安裝 redux 依賴。

$ yarn add redux@4.0.4

src/js/store 目錄下新建一個(gè) index.js 文件。

// store/index.js
import { createStore } from 'redux'

// Reducer 處理函數(shù)
const reducer = (prevState, action) => {
  const { type, payload } = action
  switch (type) {
    case 'ADD':
      // 一定要不能修改 state,而是返回一個(gè)新的副本
      // 倘若 state 是引用數(shù)據(jù)類型,一定要借助 Object.assign、對(duì)象展開運(yùn)算符(...)、其他庫的拷貝方法或者自己實(shí)現(xiàn)深拷貝方法,返回一個(gè)新副本
      return prevState + payload
    case 'SUB':
      return prevState - payload
    default:
      // default 或者未知 action 時(shí),返回舊的 state
      return prevState
  }
}

// 初始值
const initialState = 0

// 創(chuàng)建 Store(也可以不傳入 initialState 參數(shù),而將 reducer 中的 state 設(shè)置一個(gè)初始值)
const store = createStore(reducer, initialState)

// 監(jiān)聽 state 變化
// const unsubscribe = store.subscribe(() => {
//   console.log('監(jiān)聽 state 變化', store.getState())
// })

// 解除監(jiān)聽
// unsubscribe()

export default store

我們?cè)?Home 組件引入 Store,并修改成:

// pages/home/index.js
import React, { Component } from 'react'
import store from '../../store'

class Home extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }

  // Action Creator 函數(shù)
  actionCreator(type, payload) {
    return { type, payload }
  }

  handle(type, val) {
    // 創(chuàng)建 Action
    const action = this.actionCreator(type, val)
    // 派發(fā) Action
    store.dispatch(action)
    // 獲取 State 快照
    console.log(`當(dāng)前操作是 ${type},State 為:${store.getState()}`)
  }

  render() {
    return (
      <div>
        <h3>Home Component!</h3>
        <button onClick={this.handle.bind(this, 'ADD', 1)}>加一</button>
        <button onClick={this.handle.bind(this, 'SUB', 1)}>減一</button>
      </div>
    )
  }
}

export default Home

上面案例,我們做了一個(gè)很簡(jiǎn)單的加減操作。

通過 redux 提供的 createStore 函數(shù)創(chuàng)建了唯一的一個(gè) store 對(duì)象,該函數(shù)接收三個(gè)參數(shù) createStore(reducer, [preloadedState], enhancer) ,其中第一第二個(gè)分別是 reducer 函數(shù)和初始值,第三個(gè)一般是使用中間件時(shí)用到,我們后面會(huì)用到,這里暫不展開探討。(點(diǎn)這里了解更多)

Reducer 函數(shù)接收兩個(gè)參數(shù) reducer(state, action),分別是 previousState(舊狀態(tài))Action。在首次執(zhí)行 stateundefined,可以為它設(shè)置一個(gè)初始值,或者在 createStore 中傳入。它有點(diǎn)類似 Array.prototype.reduce()

借助我們?cè)?Home 組件下引入 store,并添加兩個(gè)按鈕,對(duì) storestate 做加減操作。

??

至此

我們最簡(jiǎn)單 redux 案例實(shí)現(xiàn)了,但是這個(gè)距離我們想要的,還不夠哦。

在此拋出幾個(gè)問題:

  • 如何接入我們的 Component 了,當(dāng) state 發(fā)生變化時(shí),使其自動(dòng)更新 View?
  • 組件如何共享 Store?
  • 如何查看 State 的變化?

下文繼續(xù),未完待續(xù)…

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

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