欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端的狀態(tài)管理(下)

 更新時間:2021年10月19日 11:00:21   作者:餅干_  
這篇文章主要介紹了前端的狀態(tài)管理,續(xù)上篇文章內(nèi)容,今天將從 Redux 入手逐漸拓展,需要的小伙伴可以參考一下喲

前言:

續(xù)上篇前端的狀態(tài)管理(上),沒想到很多讀者朋友們這么關(guān)注,感謝大家的支持和建議,我只是發(fā)表個人看法以及自己的一些思考也許不夠全面,使用 Vue 舉例也僅僅只是作為引路且 Vue 的關(guān)注度也是較高的。那有些朋友想聽聽除 Vuex 的其他方案,今天將從 Redux 入手逐漸拓展(如標(biāo)題一樣淺談)。

1、Redux

作為 React 全家桶的一員,Redux 試圖為 React 應(yīng)用提供可預(yù)測化的狀態(tài)管理機(jī)制。和大多數(shù)狀態(tài)管理方案一樣,Redux 的思想也是發(fā)布訂閱模式,我們還是以圖書館為例來簡單了解一下 Redux。

Redux 的基礎(chǔ)操作大致為:

  • Store(圖書館管理員)
  • State(書本)
  • Action(借書單)
  • store.dispatch(提交借書單)
  • Reducer(包裝書本)
  • store.subscribe(接收書本)

1.1、Store(圖書館管理員)

Store 可以看作是一個容器,整個應(yīng)用只有一個 Store。就好比你想要借書只能找圖書管理員。

import { createStore } from 'redux'
const store = createStore(reducer);

1.2、State(書本)

對于 State 來說他只能通過 Action 來改變(既你借書只能提交借書單來借),不應(yīng)該直接修改 State 里的值。

使用store.getState()可以得到state。

import { createStore } from 'redux'
const store = createStore(reducer)
store.getState()

1.3、Action(借書單)

你想借書咋辦?那當(dāng)然是向管理員提交借書單了。那用戶是接觸不到 State 的,只能通過 View (視圖)去操作(如點(diǎn)擊按鈕等),也就是 State 的變化對應(yīng) View 的變化,就需要 View 提交一個 Action 來通知 State 變化。(既通過提交借書單給管理員才會有接下來一系列的其他操作)

Action 是一個自定義對象,其中type屬性是約定好將要執(zhí)行的操作。

const action = {
    type: 'click',
    info: '提交借書單'
}

1.4、store.dispatch (提交借書單)

store.dispatch 是 View 發(fā)出 Action 的唯一方法,他接受一個 Action 對象(既提交借書單),只是把單的信息給了圖書管理員,他在根據(jù)單子來搜索相應(yīng)的書本。

store.dispatch(action)

1.5、Reducer(包裝書本)

Store 收到一個 Action 后,必須給出一個新的 State ,這樣 View 才會發(fā)生變化,而新的 State 的計(jì)算過程就是 Reducer 來完成的。(既拿到單子將你的書本打包裝袋等)

Reducer 是一個自定義函數(shù),它接受 Action 和當(dāng)前的 State 作為參數(shù),返回一個新的 State。

const reducer = (state, action) => {
    return `action.info: ${state}` // => 提交借書單:紅樓夢
}

store.subscribe(接收書本)
當(dāng) State 一旦發(fā)生變化,那么 store.subscribe() 就會監(jiān)聽到自動執(zhí)行更新 View。

const unsubscribe = store.subscribe(() => {
  render() {
    // 更新view 
  }
})
// 也可以取消訂閱(監(jiān)聽)
unsubscribe()

小結(jié):

相信剛接觸 Redux 的同學(xué)都會覺得 Redux 比較繁瑣,這也與他的思想有關(guān):Redux 里的一切應(yīng)該都是確定的。

盡管在 Redux 里還是沒辦法做到一切都是確定的(如異步)但是應(yīng)該保證大多數(shù)部分都是確定的包括:

  • 視圖的渲染是可確定的
  • 狀態(tài)的重建是可確定的

至于為什么要這么做,上一篇我已有提及。他的重要之處在于:便于應(yīng)用的測試,錯誤診斷和 Bug 修復(fù)。

2、狀態(tài)管理的目的

那其實(shí)大多數(shù)程序員使用 Redux 的最多的場景無非是從 A 頁面返回 B 頁面 需要保存 B 頁面的狀態(tài)。

倘若項(xiàng)目不大,用 Redux 或 Vuex 是不是會顯得有些大?我們知道在 Vue 中有提供 keep-alive 讓我們緩存當(dāng)前組件,這樣就可以解決上述的場景。

但是很遺憾在 React 中并沒有像 Vue 一樣的 keep-alive。社區(qū)中的方案普遍是改造路由,但是這種改造對于項(xiàng)目入侵過大且不易維護(hù),另外在 react-router v5 中也取消了路由鉤子。于是,對小型項(xiàng)目來說自己封裝一個函數(shù)也不失為良策。(當(dāng)然你想用 Redux 也沒問題,咱們只是探索更多方式)

還是用圖書館來舉例子,現(xiàn)在有一個圖書館管理系統(tǒng),你從列表頁(list)跳入詳情頁(detail)需要保存列表頁的狀態(tài)(如搜索欄的狀態(tài)等)。

假設(shè)你使用的技術(shù)棧是(react + antd),來手寫一個簡單粗暴的(核心是利用context來進(jìn)行跨組件數(shù)據(jù)傳遞):

// KeepAlive.js
export default function keepAliveWrapper() {
  return function keepAlive(WrappedComponent) {
    return class KeepAlive extends WrappedComponent { // ps
      constructor(props) {
        super(props)
        // do something ...
      }

      componentDidMount() {
        const {
          keepAlive: { fieldsValue },
        } = this.context
        // do something ...
        super.componentDidMount()

      }

      render() {
        // do something ...
        return super.render()
      }
    }
  }
}

這里提一下為什么要繼承原組件(// ps)

如果常規(guī)寫法返回一個類組件(class KeepAlive extends React.Component),那本質(zhì)上就是父子組件嵌套,父子組件的生命周期都會按秩序執(zhí)行,所以每當(dāng)回到列表頁獲取狀態(tài)時,會重復(fù)渲染兩次,這是因?yàn)?HOC 返回的父組件調(diào)用了原組件的方法,到導(dǎo)致列表頁請求兩次,渲染兩次。

若使 HOC(高階組件)繼承自原組件,就不會生產(chǎn)兩個生命周期交替執(zhí)行,很好的解決這個問題。

// main.jsx 根組件
import React from 'react'

const appContext = React.createContext()

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
          keepAlive: {}, // 緩存對象
          isCache: false, // 是否緩存
          fieldsValue: {} // 緩存表單值
        }
    }
    componentDidMount() {
        // 初始化
        const keepAlive = {
          isCache: this.state.isCache,
          toggle: this.toggleCache.bind(this),
          fieldsValue: this.state.fieldsValue,
        }
        this.setState({ keepAlive })
    }
    // 這里封裝一個清除狀態(tài)的方法 防止渲染警告(you can't set fields before render ...)
    // 比如 list1 => list1/detail => list2 需要將跳轉(zhuǎn)放在以下回調(diào)中并清除狀態(tài)
    toggleCache(isCache = false, payload, callback) {
        const { fieldsValue = null } = payload
        const keepAlive = {
          isCache,
          fieldsValue,
          toggle: this.toggleCache.bind(this),
        }
        const fn = typeof callback === 'function' ? callback() : void 0
        this.setState(
          {
            keepAlive,
          },
          () => {
            fn
          }
        )
    }
    render() {
        const { keepAlive } = this.state
        <appContext.Provider value={{ keepAlive }}>
            // your routes...
        </appContext.Provider>
    }

}

至于為什么不直接使用 context,而多封裝一層 keepAlive,是為了統(tǒng)一處理 context,在組件頭部中使用裝飾器這種簡潔的寫法(@keepAlive)你就立馬知道這是一個有緩存的組件(方便閱讀及維護(hù))。

// 在頁面使用時
import React from 'react'
import keepAlive from '../keepAlive'

// keepAlive的位置需要放在原組件最近的地方 
@keepAlive()
class App extends React.Component {
    constructor(props){
        super(props)
        this.state = {
            // init something...
        }
    }
    componentDidMount() {
        // do something...
        if(this.context.keepAlive.fieldsValue) {
            const { tableList } = this.context.keepAlive.fieldsValue
            console.log('緩存啦:',tableList) // 緩存啦:['1', '2']
        }
    }
    // 查看詳情
    detail = () => {
        this.context.keepAlive.fieldsValue = {
            tableList: ['1', '2']
        }
        // jump...
    }
    // 當(dāng)需要跨一級路由進(jìn)行跳轉(zhuǎn)時,如 list1 => list1/detail(下面這個方法應(yīng)該在詳情頁里) => list2,此時需要處理一下警告
    toList2 = () => {
        this.context.keepAlive.toggle(false, {}, () => {
            // jump...
        })
    }
}

在上述使用了裝飾器寫法,簡單說一下,需要先配置以下 babel 放可使用哦~

npm install -D @babel/plugin-proposal-decorators

jsconfig.json中(無則新建)配置一下:

{
    "compilerOptions": {
        "experimentalDecorators": true
    },
    "exclude": [
        "node_modules",
        "dist"
    ]
}

在 .babelrc 配置:

{
    "plugins": [
        "@babel/plugin-proposal-decorators",
        {
            "legacy": true
        }
    ]
}

上面方法比較適用剛才說的場景(從 A 頁面返回 B 頁面 需要保存 B 頁面的狀態(tài)),有人的說,你這樣還不如用 Redux Mobx 不就好了?跨路由跳轉(zhuǎn)還得手動清除狀態(tài)防止警告。。。仁者見仁,智者見智吧。自己封裝了也說明自己有所研究,不論他易或難,編程本身不就該是不斷探索嗎,哈哈。盡管你寫的可能不夠好或是咋樣,虛心接受批評就是了,畢竟厲害的人多著呢。

總結(jié):

到此這篇關(guān)于前端的狀態(tài)管理的文章就介紹到這了,更多相關(guān)前端的狀態(tài)管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

回顧上篇:淺談前端的狀態(tài)管理(上)

相關(guān)文章

  • JavaScript流程控制(循環(huán))

    JavaScript流程控制(循環(huán))

    這篇文章主要介紹了JavaScript流程控(循環(huán)),在程序中,一組被重復(fù)執(zhí)行的語句被稱之為循環(huán)體,能否繼續(xù)重復(fù)執(zhí)行,取決于循環(huán)的終止條件。由循環(huán)體及循環(huán)的終止條件組成的語句,被稱之為循環(huán)語句,更多詳細(xì)內(nèi)容請需要的小伙伴參考下面文章的具體介紹
    2021-12-12
  • JS數(shù)組方法some、every和find的使用詳情

    JS數(shù)組方法some、every和find的使用詳情

    這篇文章 要給大家介紹的是JS數(shù)組方法some、every和find的使用的一些相關(guān)資料,感興趣的小伙伴一起來學(xué)習(xí)吧
    2021-09-09
  • 微信小程序 九宮格實(shí)例代碼

    微信小程序 九宮格實(shí)例代碼

    這篇文章主要介紹了微信小程序 九宮格實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • 微信小程序中form 表單提交和取值實(shí)例詳解

    微信小程序中form 表單提交和取值實(shí)例詳解

    這篇文章主要介紹了微信小程序中form 表單提交和取值實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • JS輕量級函數(shù)式編程實(shí)現(xiàn)XDM一

    JS輕量級函數(shù)式編程實(shí)現(xiàn)XDM一

    這篇文章主要為大家介紹了JS輕量級函數(shù)式編程實(shí)現(xiàn)XDM示例詳解第1/3篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 前端JavaScript大管家 package.json

    前端JavaScript大管家 package.json

    這篇文章主要介紹了前端JavaScript大管家 package.json,在每個前端項(xiàng)目中,都有package.json文件,它是項(xiàng)目的配置文件,常見的配置有配置項(xiàng)目啟動、打包命令,聲明依賴包等,下面我們就來學(xué)習(xí) package.json的詳細(xì)內(nèi)容,需要的朋友可以參考一下
    2021-10-10
  • 微信小程序 swiper組件構(gòu)建輪播圖的實(shí)例

    微信小程序 swiper組件構(gòu)建輪播圖的實(shí)例

    這篇文章主要介紹了微信小程序 swiper組件構(gòu)建輪播圖的實(shí)例的相關(guān)資料,如有疑問請留言或者到本站社區(qū)交流討論,需要的朋友可以參考下
    2017-09-09
  • 微信小程序 圖片等比例縮放(圖片自適應(yīng)屏幕)

    微信小程序 圖片等比例縮放(圖片自適應(yīng)屏幕)

    這篇文章主要介紹了微信小程序 圖片等比例縮放(圖片自適應(yīng)屏幕)的相關(guān)資料,需要的朋友可以參考下
    2016-11-11
  • Hooks封裝與使用示例詳解

    Hooks封裝與使用示例詳解

    這篇文章主要為大家介紹了Hooks封裝與使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 微信小程序 支付功能(前端)的實(shí)現(xiàn)

    微信小程序 支付功能(前端)的實(shí)現(xiàn)

    這篇文章主要介紹了微信小程序 支付功能(前端)的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2017-05-05

最新評論