成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

震驚!用 Suspense 解決請求依賴的復雜場景居然這么簡單!

開發 前端
許多前端比較依賴把所有接口都放在父級組件中去請求的方案,這樣不管你的接口是否混亂,在前端總能處理。但是這樣的結果就是頁面組件的耦合變得更加嚴重。

有一種復雜場景 React 新手經常處理不好。

那就是一個頁面有多個模塊,每個模塊都有自己的數據需要請求。與此同時,可能部分模塊的數據還要依賴父級的異步數據才能正常請求自己的數據。如下圖所示,當我們直接訪問該頁面時,頁面請求的數據就非常多。而且這些數據還有一定的先后依賴關系。

大概數據請求的順序依次如下:

1. 自動登錄 -> 個人用戶信息,權限信息
2. 左側路由信息
3. 頁面頂層數據
4. 頁面五個模塊各自的數據

這些接口數據依賴關系比較明確,前面的接口請求完成之后,后續的接口才能正確請求。

如果頁面四個模塊的接口數據相互之間沒有關系,其實整個頁面還會簡單一些,但是很多時候復雜度往往來自于后端的不配合。前端與后端的溝通在一些團隊經常出現問題。

有的后端不愿意配合前端頁面結構修改接口,前端也溝通不下來,只能自己咬牙在混亂的接口情況下寫頁面,就導致了無論是組件的劃分也好還是頁面的復雜度也好都變得雜亂無章。從而增加了開發成本。

因此,只有在一些比較規范的團隊里,頁面五個模塊的數據解耦做得比較好。模塊之間干凈簡潔的依賴關系能有效降低開發難度。

因此許多前端比較依賴把所有接口都放在父級組件中去請求的方案,這樣不管你的接口是否混亂,在前端總能處理。但是這樣的結果就是頁面組件的耦合變得更加嚴重。

在 React 19 中,我們可以使用 Suspense 嵌套來解決這種請求之間前后依賴的方案。我們在項目中模擬了這種場景的實現。具體的演示圖如下。

一、重新考慮初始化

和之前的方案一樣,我們先定義父組件的請求接口。

const getMessage = async () => {
  const res = await fetch('https://api.chucknorris.io/jokes/random')
  return res.json()
}

然后在父組件中,將 getMessage() 執行之后返回的 promise 作為狀態存儲在 useState 中。這樣,當我點擊時,只需要重新執行依次 getMessage() 就可以更新整個組件。

const [
  messagePromise, 
  setMessagePromise
] = useState(null)

但是此時我們發現,messagePromise 并沒有初始值,因此初始化時,接口并不會請求。這種情況下,有兩種交互我們需要探討。一種是通過點擊按鈕來初始化接口。另外一種就是組件首次渲染就要初始化接口。

我們之前的案例中,使用了取巧的方式,在函數組件之外提前獲取了數據,這會導致訪問任何頁面該數據都會加載,因此并非合適的手段。

// 我們之前的案例這樣做是一種取巧的方式
const api = getMessage()

function Message() {
  ...

但是如果我們直接把 getMessage() 放在組件內部執行,也存在不小的問題。因為當組件因為其他的狀態發生變化需要重新執行時,此時 getMessage() 也會冗余的多次執行。

// 此時會冗余多次執行
const [
  messagePromise, 
  setMessagePromise
] = useState(getMessage())

理想的情況是 getMessage() 只在組件首次渲染時執行依次,后續狀態的改變就不在執行。而不需要多次執行。

我們先來考慮通過點擊事件初始化接口的交互。此時我們可以先設置 messagePrmoise 的初始值為 null。

const [
  messagePromise, 
  setMessagePromise
] = useState(null)

不過這樣做有一個小問題就是如果我將 messagePromise 值為 null 時傳遞給了子組件。那么子組件就會報錯,因此我們需要特殊處理。一種方式就是在子組件內部判斷。

const MessageOutput = ({messagePromise}) => {
  if (!messagePromise) return
  const messageContent = use(messagePromise)

或者:

// 這種寫法是在需要默認顯示狀態時的方案
const MessageOutput = ({messagePromise}) => {
  const messageContent = messagePromise ? use(messagePromise) : {value: '默認值'}

另外一種思路就是設置一個狀態,子組件基于該狀態的值來是否顯示。然后在點擊時將其設置為 true。

const [show, setShow] = useState(false)

function __clickHandler() {
  setMessagePromise(getMessage())
  setShow(true)
}
{show && <MessageContainer messagePromise={messagePromise} />}

另外一種交互思路就是初始化時就需要馬上請求數據。此時我們為了確保 getMessage() 只執行一次,可以新增一個非 state 狀態來記錄組件的初始化情況。默認值為 false,初始化之后設置為 true。

const i = useRef(false)
let __api = i.current ? null : getMessage()
const [
  messagePromise, 
  setMessagePromise
] = useState(null)

然后在 useEffect 中,將其設置為 true,表示組件已經初始化過了。

useEffect(() => {
  i.current = true
}, [])

這是利用 useState 的內部機制,初始化值只會賦值一次來做到的。從而我們可以放心更改后續 __api 的值為 null.

從這個細節的角度來說,函數組件多次執行的確會給開發帶來一些困擾,Vue3/Solid 只執行一次的機制會更舒適一些,不過處理得當也能避免這個問題。

二、Suspense 嵌套

接下來,我們需要考慮的就是 Suspense 嵌套執行的問題就行了。這個執行起來非常簡單。我們只需要將有異步請求的模塊用 Suspense 包裹起來當成一個子組件。然后該子組件可以當成一個常規的子組件作為 Suspense 組件的子組件。

例如,我們聲明一個子組件如下所示:

const getApi = async () => {
  const res = await fetch('https://api.chucknorris.io/jokes/random')
  return res.json()
}

export default function Index(props) {
  const api = getApi()

  return (
    <div>
      <div id='tips'>多個 Suspense 嵌套,子組件第一部分</div>
      <div className="content">
        <div className='_05_dou1_message'>父級消息: {props.value}</div>
        <Suspense fallback={<div>Loading...</div>}>
          <Item api={api} />
        </Suspense>
      </div>
    </div>
  )
}

const Item = ({api}) => {
  const joke = api ? use(api) : {value: 'nothing'}

  return (
    <div className='_03_a_value_update'>子級消息:{joke.value}</div>
  )
}

然后我可以將這個子組件放在 Suspense 內就可以了。

import DouPlus1 from './Dou1'
import DouPlus2 from './Dou2'
const MessageOutput = ({messagePromise}) => {
  const messageContent = use(messagePromise)
  return (
    <div>
      <p>{messageContent.value}</p>
      <DouPlus1 value={messageContent.value} />
      <DouPlus2 value={messageContent.value} />
    </div>
  )
}

在另外一個子組件中,我們還設計了內部狀態,用于實現切換按鈕,來增加頁面交互的復雜度。并且每次切換都會請求接口。

如果切換時,上一個接口沒有請求完成,React 會自己處理好數據的先后問題。不需要我們額外考慮競態條件的情況。完整代碼如下:

var tabs = ['首頁', '視頻', '探索']

export default function Index() {
  var r = useRef(false)
  var api = r.current ? null : getApi()
  const [promise, setPromise] = useState(api)
  const [current, setCurrent] = useState(0)

  useEffect(() => {
    r.current = true
  }, [])

  return (
    <div>
      <div id='tips'>多個 Suspense 嵌套,子組件第二部分</div>
      <div className="content">
        {tabs.map((item, index) => (
          <button 
            id='btn_05_item' 
            className={current == index ? 'active' : ''}
            onClick={() => {
              setCurrent(index)
              setPromise(getApi())
            }}
            key={item}
          >{item}</button>
        ))}
        
        <Suspense fallback={<div className='_05_a_value_item'>Loading...</div>}>
          <Item api={promise} />
        </Suspense>
      </div>
    </div>
  )
}

const Item = ({api}) => {
  const joke = use(api)

  return (
    <div className='_05_a_value_item'>{joke.value}</div>
  )
}

三、總結

當我們要在復雜交互的情況下使用嵌套 Suspense 來解決問題,如果我們組件劃分得當、與數據依賴關系處理得當,那么代碼就會相當簡單。不過這對于開發者來說,會有另外一個層面的要求。那就是如何合理的處理好組件歸屬問題。

許多前端頁面開發難度往往都是由于組件劃分不合理,屬性歸屬問題處理不夠到位導致的。因此 Suspense 在這個層面有了一個剛需,開發者必須要具備合理劃分組件的能力,否則即使使用了 Suspense,也依然可能導致頁面一團混亂。

責任編輯:姜華 來源: 這波能反殺
相關推薦

2022-11-11 09:41:04

連接池微服務數據庫

2025-04-08 07:00:00

C#智能家居編程

2012-04-06 09:45:41

開發

2009-03-18 10:01:15

OracleIASNoClassDefF

2024-09-20 08:14:16

2024-04-02 08:41:10

ArrayListSubList場景

2025-05-20 09:31:19

2017-11-27 12:24:02

命令行代碼指令

2024-07-05 11:47:43

2022-01-27 14:12:49

Python游戲腳本

2021-12-30 10:55:54

Python游戲腳本

2019-05-13 08:24:58

數據庫MySQLInnoDB

2024-02-27 08:14:51

Nginx跨域服務

2017-07-14 08:18:08

異構存儲復制

2019-01-30 19:02:15

Python編程語言

2017-07-10 13:31:03

異構 存儲

2024-03-18 09:24:12

RocketMQ消息模型分布式

2021-04-19 05:42:51

Mmap文件系統

2020-11-11 08:14:42

URL工具類Spring

2020-11-02 14:38:56

Java 深度學習模型
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩一区二区三区在线观看 | 久久免费精品视频 | 在线区| 欧美视频第三页 | 欧美日韩综合 | 影音先锋中文字幕在线观看 | 久久久精品网 | 午夜视频一区二区三区 | a在线免费观看视频 | 亚洲精品久久久久国产 | 成人做爰9片免费看网站 | 欧美不卡 | 亚洲区中文字幕 | 一区二区三区在线 | 三级成人在线 | 久久久久久综合 | 中文字幕免费在线 | 日韩精品四区 | 久久久久国产精品 | 日本在线中文 | 视频一区在线观看 | 蜜臀久久99精品久久久久野外 | 久久精品视频在线观看 | 日韩欧美在线播放 | 精品国产免费人成在线观看 | 成人精品国产免费网站 | 国产精品久久久久免费 | 欧美一区二区三区精品 | 日日干天天操 | 一区二区三区免费在线观看 | 99免费精品视频 | 国产午夜精品理论片a大结局 | 成人午夜精品 | av片网站| 成人黄色在线视频 | 妹子干综合 | 亚洲天堂中文字幕 | 人人干视频在线 | 成人影院免费视频 | 久久亚洲一区二区三区四区 | 国产剧情一区二区三区 |