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

Mobx實現(xiàn)React?應(yīng)用的狀態(tài)管理詳解

 更新時間:2022年12月05日 08:46:32   作者:何遇er  
這篇文章主要為大家介紹了Mobx?實現(xiàn)?React?應(yīng)用的狀態(tài)管理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

MobX

MobX 是一個狀態(tài)管理庫,它會自動收集并追蹤依賴,開發(fā)人員不需要手動訂閱狀態(tài),當(dāng)狀態(tài)變化之后 MobX 能夠精準(zhǔn)更新受影響的內(nèi)容,另外它不要求 state 是可 JSON 序列化的,也不要求state 是 immutable,MobX 推薦的數(shù)據(jù)流如下圖所示:

本文先以一個 demo 單獨介紹 Mobx 的用法,再介紹如何將 Mobx 與 React 結(jié)合實現(xiàn) React 應(yīng)用程序的狀態(tài)管理。

從一個 demo 開始

這部分用 MobX + TypeScript 實現(xiàn)一個 TODO List 的 demo,MobX 的版本為 6.5.0,TypeScript 的版本為 4.5.4,將 TypeScript 編譯器配置項 useDefineForClassFields 設(shè)置為 true。

創(chuàng)建類并將其轉(zhuǎn)化成可觀察對象

創(chuàng)建 ToDoItem 類和 ToDoList 類,ToDoItem 類的代碼如下:

import { makeObservable, observable, action } from 'mobx'
class ToDoItem {
    id: number
    name: string
    status: 0 | 1
    changeStatus(status: Status) {
        this.status = status
    }
    constructor(name: string) {
        this.id = Uid ++
        this.name = name
        this.status = 0
       // 注意這里
        makeObservable(this, {
            status: observable,
            changeStatus: action
        })
    }
}

用 makeObservable 將 ToDoItem 實例變成可觀察的,用 observable 標(biāo)記 status 字段,讓 MobX 跟蹤它的變化,changeStatus 方法用于修改 status 的值,所以用action標(biāo)記它。

ToDoList 類比 ToDoItem 類復(fù)雜一些,它收集 Todo-List Demo 需要的全部數(shù)據(jù),代碼如下:

import { makeObservable, observable, action, computed, runInAction } from 'mobx'
class ToDoList {
    searchStatus?: 0 | 1
    list: ToDoItem[] = []
    get displayList() {
        if (!this.searchStatus) {
            return this.list
        } else {
            return this.list.filter(item => item.status === this.searchStatus)
        }
    }
    changeStatus(searchStatus: Status | undefined) {
        this.searchStatus = searchStatus
    }
    addItem(name: string) {
        this.list.push(new ToDoItem(name))
    }
    async fetchInitData() {
        await waitTime()
       // 注意這里
        runInAction(() => {
            this.list = [new ToDoItem('one'), new ToDoItem('two')]
        })
    }
    constructor() {
        makeObservable(this, {
            searchStatus: observable,
            list: observable,
            displayList: computed,
            changeStatus: action,
            addItem: action
        })
    }
}

與 ToDoItem 相比,ToDoList 多使用了 computed 標(biāo)記,這是因為 displayList 的值由 searchStatus 和 list 通過一個純函數(shù)計算而來,所以它被標(biāo)記為 computed。fetchInitData 是一個異步方法,在其中用 runInAction 創(chuàng)建一個立即執(zhí)行的 action 去修改 list 的值,從 fetchInitData 的實現(xiàn)可以看出,異步修改 state 和同步修改 state 沒有差別,只要保證 state 是在 action 中修改的即可。

使用可觀察對象

在上一步的 ToDoList 和 ToDoItem 的構(gòu)造函數(shù)中,我們調(diào)用了 makeObservable 方法,并用合適的注解去標(biāo)記實例字段,接下來用一段代碼驗證 MobX 是否按照要求跟蹤state的變化。代碼如下:

import { autorun} from 'mobx'
autorun(() => { console.log(toDoList.list.length) }) // line A
autorun(() => { console.log(toDoList.list) }) // line B

autorun 接收一個函數(shù),該函數(shù)同步執(zhí)行過程中訪問的 state 或計算值發(fā)生變化時,它會自動運(yùn)行,另外,調(diào)用 autorun 時,該函數(shù)也會運(yùn)行一次。使用 toDoList.addItem 方法往 list 數(shù)組中 push 一個事項,你會發(fā)現(xiàn)上述 line A 的函數(shù)會運(yùn)行,但是 line B 的函數(shù)不會運(yùn)行;使用 toDoList.fetchInitData 方法給 list 數(shù)組賦值,line A 和 line B 的函數(shù)都會運(yùn)行,出現(xiàn)這種差異是因為 autorun 使用全等(===)運(yùn)算符確定兩個值是否相等,但它認(rèn)為 NaN 等于 NaN 。

用如下一段代碼驗證 MobX 是否按照要求跟蹤 ToDoItem 實例的 state 的變化:

import { autorun} from 'mobx'
autorun(() => {
  if (toDoList.list.length) {
       console.log(toDoList.list[0]?.status)
   }
})
reaction(() => toDoList.list.length, () => {
  toDoList.list[0].changeStatus(1)// 修改status的值
})

當(dāng) reaction 的第一個參數(shù)返回 true 時,它的第二個參數(shù)會自動執(zhí)行,上述代碼在 reaction 中修改 toDoItem 的 status 字段,修改之后 autorun 能成功運(yùn)行一次。

MobX 與 React 集成

現(xiàn)在將上一步的 TODO List 與 React 結(jié)合,為此需要安裝 mobx-react-lite 或 mobx-react,mobx-react 比 mobx-react-lite 的功能更多,同時它的體積也更大,如果你的項目只使用函數(shù)組件,那么推薦安裝 mobx-react-lite 而非 mobx-react,為了演示更多的用法本小節(jié)安裝 mobx-react。另外,本小節(jié)會用到裝飾器語法,所以要將 TypeScript 編譯器配置項 experimentalDecorators 設(shè)置為true。下面是一個 MobX + React 的簡單示例:

import { observer } from 'mobx-react'
import toDoList, { Status } from '../../mobx/todo'
const ToDoListDemoGlobalInstance= observer(
  class extends React.Component<{}, {}> {
    componentDidMount() {
     // 3s之后修改 searchStatus 的值
      setTimeout(() => {
        toDoList.changeStatus(Status.finished)
      }, 3000);
    }
    render() {
      return (
        <div>searchStatus: {toDoList.searchStatus}</div>
      )
    }
  }
)

observer 是一個高階組件,它會訂閱組件在渲染期間訪問的可觀察對象,可觀察對象指的是用 makeAutoObservable 、makeObservable 或 observable 轉(zhuǎn)換之后的對象,當(dāng)組件渲染期間訪問的 state 和計算值發(fā)生變化時,組件會重新渲染。上述代碼,組件被裝載 3s 后將修改 searchStatus 的值,由于 render 方法訪問了 searchStatus 的值,所以組件會重新渲染。observer 除了以高階組件的形式使用之外,還能以裝飾器的形式使用。

在組件中使用可觀察對象

下面介紹 6 種在組件中使用 MobX 可觀察對象的寫法。

1. 訪問全局的類實例

上一個示例代碼便是在組件中直接訪問全局的類實例,在這里不再舉更多的示例代碼。

2. 通過 props

這種方式是指將可觀察對象通過 props 的形式傳遞到組件中,代碼如下:

import { observer } from 'mobx-react'
import toDoList, { Status } from '../../mobx/todo'
@observer
class ToDoListDemoByProps extends React.Component<{toDoList: ToDoList}, {}> {
  componentDidMount() {
    setTimeout(() => {
      toDoList.changeStatus(Status.finished)
    }, 3000);
  }
  render() {
   // 讀取props中的可觀察對象
    return (
      <div>ToDoListDemoByProps - searchStatus: {this.props.toDoList.searchStatus}</div>
    )
  }
}
//使用ToDoListDemoByProps 
<ToDoListDemoByProps toDoList={toDoList}/>

3. 通過 React Context

這種方式是指通過 React Context 讓可觀察對象在整個被 Context.Provider 包裹的組件樹中共享,代碼如下:

import { observer } from 'mobx-react'
import toDoList, { Status, ToDoList } from '../../mobx/todo'
// 創(chuàng)建一個用observer包裹的函數(shù)組件
const ToDoListDemoByContext = observer(() => {
 // 在函數(shù)組件中使用Context
  const context = useContext(todoContext);
  useEffect(() => {
    setTimeout(() => {
      context.changeStatus(Status.finished)
    }, 3000);
  })
  return (
    <div>ToDoListDemoByContext - searchStatus: {context.searchStatus}</div>
  )
})
// 往Context傳值
<todoContext.Provider value={toDoList}>
   <ToDoListDemoByContext/>
</todoContext.Provider>

4. 在組件中實例化 observable class 并存儲它的實例

這種方式指的是在組件作用域中實例化類,并且將結(jié)果保存到組件的某個字段中,如果在函數(shù)組件中使用這種方式,那么還需要用到 useState。代碼如下:

const ToDoListFuncDemoLocalInstance= observer(() => {
  // 實例化類
  const [ todoList ] = useState(() => new ToDoList())
  useEffect(() => {
    setTimeout(() => {
      // 使用實例方法更新狀態(tài)
      todoList.changeStatus(Status.finished)
    }, 3000);
  })
  return (
    <div>ToDoListDemoLocalInstance - searchStatus: {todoList.searchStatus}</div>
  )
})

對于類組件而言,只需要將 new ToDoList() 的結(jié)果保存在它的實例屬性上,之后在組件中訪問該實例屬性,代碼如下:

@observer
class ToDoListClassDemoLocalInstance extends React.Component<{}, {}> {
  todoList = new ToDoList()
  // other
}

5. 在組件中調(diào)用 observable 方法創(chuàng)建可觀察對象

這種方式不使用類去創(chuàng)建可觀察對象,而是使用 observable 方法創(chuàng)建可觀察對象,與第 4 種方式一樣,如果在函數(shù)組件中還要用到 useState,代碼如下

import { observable } from 'mobx'
const LocalObservableDemo = observer(() => {
 // 調(diào)用observable
  const [counter] = useState(() => observable({
    count: 0,
    addCount() {
      this.count ++
    }
  }))
  return <>
    <div>{counter.count}</div>
    <button onClick={() => counter.addCount()}>add</button>
  </>
})

上述代碼使用 mobx 導(dǎo)出的 observable 方法創(chuàng)建一個可觀察對象,并在函數(shù)組件使用該對象,當(dāng)它的 count 屬性值發(fā)生變化時,組件將重新渲染。對于類組件而言只需要將 observable 函數(shù)的結(jié)果保存到實例屬性上即可。

6. 在函數(shù)組件中使用 useLocalObservable

useLocalObservable 是 useState + observable 簡寫版本,只能在函數(shù)組件中使用,代碼如下:

import { observer, useLocalObservable } from 'mobx-react'
const UseLocalObservableDemo = observer(() => {
  const counter = useLocalObservable(() => ({
    count: 0,
    addCount() {
      this.count ++
    }
  }))
  return <>
    <div>{counter.count}</div>
    <button onClick={() => counter.addCount()}>add</button>
  </>
})

對于函數(shù)組件而言,useLocalObservable 只是一個自定義Hook,它返回一個可觀察對象。

有多種方式讓組件在渲染階段使用可觀察對象,不管是哪種方式,組件都必須具備觀察能力,否則,當(dāng)渲染期間訪問的 state 和計算值發(fā)生變化時,組件不會重新渲染。筆者在使用 MobX 做狀態(tài)管理時,最常用的方式是第 1 和第 2 種。第 4、5、6 種方式必要性不大。

讓組件具備觀察能力

observer 是讓組件具備觀察能力最常見的方式,在這里介紹另一種讓組件具備觀察能力的方式,即:Observer組件。用法如下:

import { Observer } from 'mobx-react'
class ObservableDemo extends React.Component<{},{}> {
  render() {
    return (
    <>
      <div>{toDoList.searchStatus || '-'}</div>  {/** lineA */}
      <Observer>
	{() => <div>{toDoList.searchStatus || '-'}</div>} {/** lineB */}
	</Observer>
    </>
    )
  }
}

Observer 組件會創(chuàng)建一個匿名的觀察區(qū)域,在上述代碼中,如果 toDoList.searchStatus 的值發(fā)生變化,那么 lineB 會重新渲染,但是 lineA 不會重新渲染。

總結(jié)

將 MobX 與 React 結(jié)合在一起的關(guān)鍵在于用 observer 包裹組件以及在組件中讀取可觀察對象,observer 不關(guān)心可觀察對象從哪里來,也不關(guān)心如何讀取可觀察對象,只關(guān)心在組件中可觀察對象是否可讀。對于習(xí)慣面向?qū)ο缶幊痰墓こ處煻裕?MobX 做狀態(tài)管理會比用 Redux 做狀態(tài)管理更得心應(yīng)手。

以上就是Mobx 實現(xiàn) React 應(yīng)用的狀態(tài)管理的詳細(xì)內(nèi)容,更多關(guān)于Mobx React 應(yīng)用狀態(tài)管理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • react native圖片解析流程詳解

    react native圖片解析流程詳解

    這篇文章主要為大家介紹了react native圖片解析流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 一文詳解ReactNative狀態(tài)管理rematch使用

    一文詳解ReactNative狀態(tài)管理rematch使用

    這篇文章主要為大家介紹了ReactNative狀態(tài)管理rematch使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • React Fiber與調(diào)和深入分析

    React Fiber與調(diào)和深入分析

    Fiber可以理解為一個執(zhí)行單元,每次執(zhí)行完一個執(zhí)行單元,React Fiber就會檢查還剩多少時間,如果沒有時間則將控制權(quán)讓出去,然后由瀏覽器執(zhí)行渲染操作,這篇文章主要介紹了React Fiber架構(gòu)原理剖析,需要的朋友可以參考下
    2022-11-11
  • react使用antd的上傳組件實現(xiàn)文件表單一起提交功能(完整代碼)

    react使用antd的上傳組件實現(xiàn)文件表單一起提交功能(完整代碼)

    最近在做一個后臺管理項目,涉及到react相關(guān)知識,項目需求需要在表單中帶附件提交,怎么實現(xiàn)這個功能呢?下面小編給大家?guī)砹藃eact使用antd的上傳組件實現(xiàn)文件表單一起提交功能,一起看看吧
    2021-06-06
  • react解析html字符串方法實現(xiàn)

    react解析html字符串方法實現(xiàn)

    在使用reactjs庫的時候,會遇到將一段html的字符串,然后要將它插入頁面中以html的形式展現(xiàn),本文主要介紹了react解析html字符串方法實現(xiàn),感興趣的可以了解一下
    2023-12-12
  • React 高階組件入門介紹

    React 高階組件入門介紹

    本篇文章主要介紹了React高階組件入門介紹,這篇文章中我們詳細(xì)的介紹了什么是高階組件,如何使用高階組件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • React 組件間的通信示例

    React 組件間的通信示例

    這篇文章主要介紹了React 組件間的通信示例,主要通信劃分為三種,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • Router添加路由攔截方法講解

    Router添加路由攔截方法講解

    在vue項目中使用vue-router做頁面跳轉(zhuǎn)時,路由的方式有兩種,一種是靜態(tài)路由,另一種是動態(tài)路由。而要實現(xiàn)對路由的控制需要使用vuex和router全局守衛(wèi)進(jìn)行判斷攔截
    2023-03-03
  • React中mobx和redux的區(qū)別及說明

    React中mobx和redux的區(qū)別及說明

    這篇文章主要介紹了React中mobx和redux的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • React?Streaming?SSR原理示例深入解析

    React?Streaming?SSR原理示例深入解析

    這篇文章主要為大家介紹了React?Streaming?SSR原理示例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12

最新評論