日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

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

來源: 責(zé)編: 時(shí)間:2024-06-11 17:52:06 192觀看
導(dǎo)讀有一種復(fù)雜場景 React 新手經(jīng)常處理不好。那就是一個(gè)頁面有多個(gè)模塊,每個(gè)模塊都有自己的數(shù)據(jù)需要請求。與此同時(shí),可能部分模塊的數(shù)據(jù)還要依賴父級(jí)的異步數(shù)據(jù)才能正常請求自己的數(shù)據(jù)。如下圖所示,當(dāng)我們直接訪問該頁面時(shí),

有一種復(fù)雜場景 React 新手經(jīng)常處理不好。dZB28資訊網(wǎng)——每日最新資訊28at.com

那就是一個(gè)頁面有多個(gè)模塊,每個(gè)模塊都有自己的數(shù)據(jù)需要請求。與此同時(shí),可能部分模塊的數(shù)據(jù)還要依賴父級(jí)的異步數(shù)據(jù)才能正常請求自己的數(shù)據(jù)。如下圖所示,當(dāng)我們直接訪問該頁面時(shí),頁面請求的數(shù)據(jù)就非常多。而且這些數(shù)據(jù)還有一定的先后依賴關(guān)系。dZB28資訊網(wǎng)——每日最新資訊28at.com

dZB28資訊網(wǎng)——每日最新資訊28at.com

一、重新考慮初始化

和之前的方案一樣,我們先定義父組件的請求接口。dZB28資訊網(wǎng)——每日最新資訊28at.com

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

然后在父組件中,將 getMessage() 執(zhí)行之后返回的 promise 作為狀態(tài)存儲(chǔ)在 useState 中。這樣,當(dāng)我點(diǎn)擊時(shí),只需要重新執(zhí)行依次 getMessage() 就可以更新整個(gè)組件。dZB28資訊網(wǎng)——每日最新資訊28at.com

const [  messagePromise,   setMessagePromise] = useState(null)

但是此時(shí)我們發(fā)現(xiàn),messagePromise 并沒有初始值,因此初始化時(shí),接口并不會(huì)請求。這種情況下,有兩種交互我們需要探討。一種是通過點(diǎn)擊按鈕來初始化接口。另外一種就是組件首次渲染就要初始化接口。dZB28資訊網(wǎng)——每日最新資訊28at.com

我們之前的案例中,使用了取巧的方式,在函數(shù)組件之外提前獲取了數(shù)據(jù),這會(huì)導(dǎo)致訪問任何頁面該數(shù)據(jù)都會(huì)加載,因此并非合適的手段。dZB28資訊網(wǎng)——每日最新資訊28at.com

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

但是如果我們直接把 getMessage() 放在組件內(nèi)部執(zhí)行,也存在不小的問題。因?yàn)楫?dāng)組件因?yàn)槠渌臓顟B(tài)發(fā)生變化需要重新執(zhí)行時(shí),此時(shí) getMessage() 也會(huì)冗余的多次執(zhí)行。dZB28資訊網(wǎng)——每日最新資訊28at.com

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

理想的情況是 getMessage() 只在組件首次渲染時(shí)執(zhí)行依次,后續(xù)狀態(tài)的改變就不在執(zhí)行。而不需要多次執(zhí)行。dZB28資訊網(wǎng)——每日最新資訊28at.com

我們先來考慮通過點(diǎn)擊事件初始化接口的交互。此時(shí)我們可以先設(shè)置 messagePrmoise 的初始值為 null。dZB28資訊網(wǎng)——每日最新資訊28at.com

const [  messagePromise,   setMessagePromise] = useState(null)

不過這樣做有一個(gè)小問題就是如果我將 messagePromise 值為 null 時(shí)傳遞給了子組件。那么子組件就會(huì)報(bào)錯(cuò),因此我們需要特殊處理。一種方式就是在子組件內(nèi)部判斷。dZB28資訊網(wǎng)——每日最新資訊28at.com

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

或者:dZB28資訊網(wǎng)——每日最新資訊28at.com

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

另外一種思路就是設(shè)置一個(gè)狀態(tài),子組件基于該狀態(tài)的值來是否顯示。然后在點(diǎn)擊時(shí)將其設(shè)置為 true。dZB28資訊網(wǎng)——每日最新資訊28at.com

const [show, setShow] = useState(false)function __clickHandler() {  setMessagePromise(getMessage())  setShow(true)}
{show && <MessageContainer messagePromise={messagePromise} />}

另外一種交互思路就是初始化時(shí)就需要馬上請求數(shù)據(jù)。此時(shí)我們?yōu)榱舜_保 getMessage() 只執(zhí)行一次,可以新增一個(gè)非 state 狀態(tài)來記錄組件的初始化情況。默認(rèn)值為 false,初始化之后設(shè)置為 true。dZB28資訊網(wǎng)——每日最新資訊28at.com

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

然后在 useEffect 中,將其設(shè)置為 true,表示組件已經(jīng)初始化過了。dZB28資訊網(wǎng)——每日最新資訊28at.com

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

這是利用 useState 的內(nèi)部機(jī)制,初始化值只會(huì)賦值一次來做到的。從而我們可以放心更改后續(xù) __api 的值為 null.dZB28資訊網(wǎng)——每日最新資訊28at.com

從這個(gè)細(xì)節(jié)的角度來說,函數(shù)組件多次執(zhí)行的確會(huì)給開發(fā)帶來一些困擾,Vue3/Solid 只執(zhí)行一次的機(jī)制會(huì)更舒適一些,不過處理得當(dāng)也能避免這個(gè)問題。dZB28資訊網(wǎng)——每日最新資訊28at.com

二、Suspense 嵌套

接下來,我們需要考慮的就是 Suspense 嵌套執(zhí)行的問題就行了。這個(gè)執(zhí)行起來非常簡單。我們只需要將有異步請求的模塊用 Suspense 包裹起來當(dāng)成一個(gè)子組件。然后該子組件可以當(dāng)成一個(gè)常規(guī)的子組件作為 Suspense 組件的子組件。dZB28資訊網(wǎng)——每日最新資訊28at.com

例如,我們聲明一個(gè)子組件如下所示:dZB28資訊網(wǎng)——每日最新資訊28at.com

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'>多個(gè) Suspense 嵌套,子組件第一部分</div>      <div className="content">        <div className='_05_dou1_message'>父級(jí)消息: {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'>子級(jí)消息:{joke.value}</div>  )}

然后我可以將這個(gè)子組件放在 Suspense 內(nèi)就可以了。dZB28資訊網(wǎng)——每日最新資訊28at.com

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>  )}

在另外一個(gè)子組件中,我們還設(shè)計(jì)了內(nèi)部狀態(tài),用于實(shí)現(xiàn)切換按鈕,來增加頁面交互的復(fù)雜度。并且每次切換都會(huì)請求接口。dZB28資訊網(wǎng)——每日最新資訊28at.com

dZB28資訊網(wǎng)——每日最新資訊28at.com

如果切換時(shí),上一個(gè)接口沒有請求完成,React 會(huì)自己處理好數(shù)據(jù)的先后問題。不需要我們額外考慮競態(tài)條件的情況。完整代碼如下:dZB28資訊網(wǎng)——每日最新資訊28at.com

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'>多個(gè) 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>  )}

三、總結(jié)

當(dāng)我們要在復(fù)雜交互的情況下使用嵌套 Suspense 來解決問題,如果我們組件劃分得當(dāng)、與數(shù)據(jù)依賴關(guān)系處理得當(dāng),那么代碼就會(huì)相當(dāng)簡單。不過這對于開發(fā)者來說,會(huì)有另外一個(gè)層面的要求。那就是如何合理的處理好組件歸屬問題。dZB28資訊網(wǎng)——每日最新資訊28at.com

許多前端頁面開發(fā)難度往往都是由于組件劃分不合理,屬性歸屬問題處理不夠到位導(dǎo)致的。因此 Suspense 在這個(gè)層面有了一個(gè)剛需,開發(fā)者必須要具備合理劃分組件的能力,否則即使使用了 Suspense,也依然可能導(dǎo)致頁面一團(tuán)混亂。dZB28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-93090-0.html震驚!用 Suspense 解決請求依賴的復(fù)雜場景居然這么簡單!

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: C++ 首度超越 C 語言僅次榜首 Python,TIOBE 編程指數(shù)六月排行榜公布

下一篇: PHP 服務(wù)實(shí)現(xiàn)性能剖析、跟蹤和可觀察性14444444444444】=102102102102102102102102102102102102102102102102實(shí)踐

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 汉阴县| 大余县| 东兰县| 内黄县| 且末县| 南华县| 古田县| 霍邱县| 嘉鱼县| 龙陵县| 伊宁市| 小金县| 浮梁县| 麻阳| 闻喜县| 镇原县| 汉川市| 区。| 尉氏县| 巴彦县| 腾冲县| 天气| 五河县| 襄垣县| 安溪县| 刚察县| 宜川县| 古交市| 吉安市| 临江市| 邹城市| 遵义市| 马关县| 岳普湖县| 伊金霍洛旗| 若尔盖县| 全州县| 长顺县| 吉首市| 营口市| 五峰|