溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

react18中的Transition怎么用

發(fā)布時(shí)間:2022-03-25 11:05:34 來(lái)源:億速云 閱讀:284 作者:iii 欄目:web開(kāi)發(fā)

這篇文章主要介紹“react18中的Transition怎么用”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“react18中的Transition怎么用”文章能幫助大家解決問(wèn)題。

react18中的Transition怎么用

React 18中,引入了一個(gè)新概念——transition,由此帶來(lái)了一個(gè)新的API——startTransition和兩個(gè)新的hooks——useTransitionusedeferredValue,本文由此展開(kāi)使用嘗鮮介紹。

1. 總覽

本文分為4部分進(jìn)行:

  • tansition 產(chǎn)生初衷

  • startTransition 使用和介紹

  • useTransition 使用和介紹

  • useDeferredValue 使用和介紹

2. transition產(chǎn)生初衷

transtion 直接翻譯為 過(guò)渡。tansition本質(zhì)上是為了解決渲染并發(fā)問(wèn)題所提出。在React中一旦組件狀態(tài)改變并觸發(fā)了重新渲染,則無(wú)法停止渲染。直到組件重新渲染完畢,頁(yè)面才能繼續(xù)響應(yīng)用戶(hù)的交互。

為此react 18中更新都可以劃分為以下兩類(lèi):

  • 緊急更新(urgent update):用戶(hù)期望馬上響應(yīng)的更新操作,例如鼠標(biāo)單擊或鍵盤(pán)輸入。

  • 過(guò)渡更新(transition update):一些延遲可以接受的更新操作,如查詢(xún)時(shí),搜索推薦、搜索結(jié)果的展示等。

// 被startTransiton標(biāo)記后為過(guò)渡更新
startTransition(()=> {
    // 非緊急更新,會(huì)被降低優(yōu)先級(jí),延遲執(zhí)行
    setQueryValue(inputValue)
})

// 未被標(biāo)記則馬上執(zhí)行
setInputValue(inputValue)

在react 18中被startTrionstion標(biāo)記的更新,即為過(guò)渡更新(執(zhí)行的優(yōu)先級(jí)被降低),此時(shí)react會(huì)根據(jù)內(nèi)部的調(diào)度機(jī)制延遲執(zhí)行內(nèi)部的state更新。

開(kāi)發(fā)中開(kāi)發(fā)者可以通過(guò)transition hook決定哪些更新被標(biāo)記為transition事件。一旦被標(biāo)記則代表為低優(yōu)先級(jí)執(zhí)行,即react知道該state可以延遲更新,通過(guò)區(qū)分更新優(yōu)先級(jí),讓高優(yōu)先級(jí)的事件保持響應(yīng),提高用戶(hù)交互體驗(yàn),保持頁(yè)面響應(yīng)

3. startTransiton

startTransiton使用介紹

const handleClick = () => {
    // startTransition包裹標(biāo)記為低優(yōu)先級(jí)更新
    startTransition(()=> {
        setQueryValue(inputValue)
    })
    
    // 未被標(biāo)記則馬上執(zhí)行
    setInputValue(inputValue)
}

首先我們來(lái)介紹下最簡(jiǎn)單的startTransition

  • startTransiton 是一個(gè)接受回調(diào)的函數(shù),用于告知React需要延遲更新的state。

  • 如果某個(gè)state的更新會(huì)導(dǎo)致組件掛起,則應(yīng)該包裹在startTransition中

通過(guò)演示對(duì)比

這是一個(gè)對(duì)輸入字符后展示搜索結(jié)果的場(chǎng)景模擬,通過(guò)偽造大量搜索結(jié)果,模擬容易卡頓的情況。

我們?cè)囍B續(xù)輸入123,監(jiān)聽(tīng)搜索框值value變化(urgent update)和搜索值searchVal變化(transition update)并輸出到控制欄。

import React, { useEffect, useState, startTransition } from 'react';
import './App.css'

const SearchResult = (props) => {
    const resultList = props.query
        ? Array.from({ length: 10000 }, (_, index) => ({
            id: index,
            keyword: `${props.query} -- 搜索結(jié)果${index}`,
        })) : [];
    return resultList.map(({ id, keyword }) => (
        <li key={id}>{keyword}</li>
    ))
}

const App = () => {
    const [type, setTpye] = useState(1)
    const [value, setValue] = useState('');
    const [searchVal, setSearchVal] = useState('-');

    useEffect(() => {
        // 監(jiān)聽(tīng)搜索值改變
        console.log('對(duì)搜索值更新的響應(yīng)++++++' + searchVal + '+++++++++++')
    }, [searchVal])

    useEffect(() => {
        console.log('對(duì)輸入框值更新的響應(yīng)-----' + value + '-------------')
        if (type === 1) {
            setSearchVal(value || '-')
        }
        if (type === 2) {
            startTransition(() => {
                setSearchVal(value || '-')
            })
       }
    }, [value, type]);

    return (
        <div className='App'>
            <input value={value} onChange={e => setValue(e.target.value)} />
            <div className={`type_button ${type === 1 ? 'type_button_checked' : ''}`} onClick={() => setTpye(1)}>normal</div>
            <div className={`type_button ${type === 2 ? 'type_button_checked' : ''}`} onClick={() => setTpye(2)}>transiton</div>
            <ul>
                <SearchResult query={searchVal}></SearchResult>
            </ul>
        </div>
    );
};

普通模式下

react18中的Transition怎么用

如圖所示:連續(xù)輸入字符123,當(dāng)?shù)谝粋€(gè)字符輸入后,搜索值馬上響應(yīng),列表渲染立刻開(kāi)始,造成卡頓輸入框停止了對(duì)用戶(hù)輸入的響應(yīng),直到渲染結(jié)束,輸入框才繼續(xù)響應(yīng)。

使用startTransition后

如圖所示:連續(xù)輸入字符123,輸入框不斷響應(yīng),搜索值的響應(yīng)被延后,保證頁(yè)面反饋,直到輸入結(jié)束,才開(kāi)始響應(yīng)搜索值,渲染搜索結(jié)果,保持頁(yè)面響應(yīng)。

4. useTransiton

useTransiton使用介紹

import { useTransiton } from 'react'

const [isPending, startTransition] = useTransiton({timeoutMs: 2000})
// 例如, 在pending狀態(tài)下,您可以展示一個(gè)Spinner
{ isPending ? < Spinner /> : null }
  • startTransition 是一個(gè)接受回調(diào)的函數(shù),用于告知React需要延遲更新的state。

  • isPending 是一個(gè)布爾值,這是react告知我們是否等待過(guò)渡完成的方式。

  • useTransition 接受帶有 timeoutMs 的延遲響應(yīng)的值,如果給定的timeoutMs內(nèi)未完成,它將會(huì)強(qiáng)制執(zhí)行startTransition回調(diào)函數(shù)內(nèi)state的更新。

useTransiton簡(jiǎn)單分析

我們通過(guò)偽代碼理解下useTransition。

function useTransition(){
    const [isPending, setPending] = mountState(false);
    const start = (callback)=>{
        setPending(true);
        // Scheduler.unstable_next 通過(guò) transiton 模式,低優(yōu)先級(jí)調(diào)度執(zhí)行回調(diào)函數(shù)
        // 可以降低更新的優(yōu)先級(jí)。如果回調(diào)中觸發(fā)的更新優(yōu)先級(jí)會(huì)比較低,
        // 它會(huì)讓位為高優(yōu)先級(jí)的更新,或者當(dāng)前事務(wù)繁忙時(shí),調(diào)度到下一空閑期再應(yīng)用。
        Scheduler.unstable_next(() => {
            const prevTransition = ReactCurrentBatchConfig.transition;
            ReactCurrentBatchConfig.transition = 1;
            try {
                setPending(false);
                //實(shí)行回調(diào)函數(shù)
                callback();
            } finally {
                ReactCurrentBatchConfig.transition = prevTransition;
            }
        })
    }
    return [isPending, start];
}

startTransition執(zhí)行過(guò)程中,會(huì)觸發(fā)兩次setPending ,一次在transition=1之前,一次在之后。startTransition被調(diào)用時(shí)setPending(true),當(dāng)startTransition內(nèi)部的回調(diào)函數(shù)執(zhí)行時(shí)transiton過(guò)渡任務(wù)更新setPending(false)。react內(nèi)部可以根據(jù)pending值的變化準(zhǔn)確把握等待的過(guò)渡時(shí)間,并依此判斷是否超過(guò)了timeoutMs(如果有傳入)強(qiáng)制執(zhí)行更新。

5. useDeferredValue

useDeferredValue使用介紹

const [value, setValue] = useState('')
// defferedValue值延后于state更新
const deferredValue = useDeferredValue(value, {timeoutMs: 2000})
  • useDeferredValue 返回一個(gè)延遲響應(yīng)的狀態(tài),可以設(shè)置最長(zhǎng)延遲時(shí)間timeoutMs

  • 可以傳入可選的timeoutMs,如果給定的timeoutMs內(nèi)未完成,它將會(huì)強(qiáng)制更新。

  • 與useTransition的不同: useTransition是處理一段邏輯,而useDeferred是產(chǎn)生一個(gè)新?tīng)顟B(tài)。

useDeferredValue的使用

import React, { useEffect, useState, useTransition, useDeferredValue } from 'react';
import './App.css'

const SearchResult = (props) => {
    const resultList = props.query
        ? Array.from({ length: 10000 }, (_, index) => ({
            id: index,
            keyword: `${props.query} -- 搜索結(jié)果${index}`,
        })) : [];
    return resultList.map(({ id, keyword }) => (
        <li key={id}>{keyword}</li>
    ))
}

const App = () => {
    const [value, setValue] = useState('');
    const searchValue = useDeferredValue(value, { timeoutMs: 2000 });

    useEffect(() => {
        console.log('對(duì)輸入框值的響應(yīng)--------' + value + '---------------')
    }, [value])

    useEffect(() => {
        // 監(jiān)聽(tīng)搜索值改變
        console.log('對(duì)搜索值的更新響應(yīng)++++++' + searchValue + '+++++++++++')
    }, [searchValue])

    return (
        <div className='App'>
            <input value={value} onChange={e => setValue(e.target.value)} />
        <div className={`type_button type_button_checked`}>useDeferredValue</div>
        <ul>
            <SearchResult query={searchValue}></SearchResult>
        </ul>
    </div>
    );
};

useDeferredValue簡(jiǎn)單分析

我們通過(guò)偽代碼理解下useDeferredValue

function useDeferredValue(value){
    const [prevValue, setValue] = updateState(value);
    updateEffect(() => {
        // 在 useEffect 中通過(guò) transition 模式來(lái)更新 value 。
        Scheduler.unstable_next(() => {
            const prevTransition = ReactCurrentBatchConfig.transition;
            ReactCurrentBatchConfig.transition = 1;
            try {
                setValue(value);
            } finally {
                ReactCurrentBatchConfig.transition = prevTransition;
            }
         })
    }, [value]);
    return prevValue;
}

useDeferredValue通過(guò)useEffect監(jiān)聽(tīng)傳入值的變化,然后通過(guò)過(guò)渡任務(wù)執(zhí)行值的改變。這樣保證defrredValue的更新滯后于setState,同時(shí)符合過(guò)渡更新的原則,因?yàn)槭峭ㄟ^(guò)transition 調(diào)度機(jī)制執(zhí)行的。

關(guān)于“react18中的Transition怎么用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI