首頁  >  文章  >  web前端  >  淺析react18中的新概念Transition

淺析react18中的新概念Transition

青灯夜游
青灯夜游轉載
2022-03-25 10:52:462400瀏覽

本篇文章帶大家了解react18的新概念Transition,簡單介紹一下新API:startTransition和新hooks:useTransition和usedeferredValue的使用方法,希望對大家有幫助!

淺析react18中的新概念Transition

React 18中,引入了一個新概念-transition,由此帶來了一個新的API-startTransition和兩個新的hooks——useTransitionusedeferredValue,本文由此展開使用嚐鮮介紹。 【相關推薦:Redis影片教學

1. 總覽表

本文分為4部分進行:

  • tansition 產生初衷
  • startTransition 使用與介紹
  • ##useTransition 使用與介紹
  • useDeferredValue 使用和介紹

#2. transition產生初衷

#transtion 直接翻譯為過渡。 tansition本質上是為了解決渲染並發問題所提出。在React中一旦元件狀態改變並觸發了重新渲染,則無法停止渲染。直到元件重新渲染完畢,頁面才能繼續回應使用者的互動。

為此react 18中更新都可以分割為以下兩類:

  • #緊急更新(urgent update):使用者期望馬上回應的更新操作,例如滑鼠單擊或鍵盤輸入。
  • 過渡更新(transition update):一些延遲可以接受的更新操作,如查詢時,搜尋推薦、搜尋結果的展示等。
  • // 被startTransiton标记后为过渡更新
    startTransition(()=> {
        // 非紧急更新,会被降低优先级,延迟执行
        setQueryValue(inputValue)
    })
    
    // 未被标记则马上执行
    setInputValue(inputValue)
在react 18中被

startTrionstion標記的更新,即為過渡更新(執行的優先權被降低),此時react會根據內部的調度機制延遲執行內部的state更新。

開發中開發者可以透過transition hook決定哪些更新被標記為transition事件。一旦被標記則代表為低優先權執行,即react知道該state可以延遲更新,

透過區分更新優先權,讓高優先權的事件保持回應,提高使用者互動體驗,維持頁面響應

3. startTransiton

#startTransiton使用介紹

const handleClick = () => {
    // startTransition包裹标记为低优先级更新
    startTransition(()=> {
        setQueryValue(inputValue)
    })
    
    // 未被标记则马上执行
    setInputValue(inputValue)
}

首先我們來介紹最簡單的

startTransition

    startTransiton 是一個接受回呼的函數,用於告知React需要延遲更新的state。
  • 如果某個state的更新會導致元件掛起,則應該包裹在startTransition中

透過示範對比

#這是一個對輸入字元後展示搜尋結果的場景模擬,透過偽造大量搜尋結果,模擬容易卡頓的情況。

我們試著連續輸入123,監聽搜尋框值

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} -- 搜索结果${index}`,
        })) : [];
    return resultList.map(({ id, keyword }) => (
        <li key={id}>{keyword}</li>
    ))
}

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

    useEffect(() => {
        // 监听搜索值改变
        console.log(&#39;对搜索值更新的响应++++++&#39; + searchVal + &#39;+++++++++++&#39;)
    }, [searchVal])

    useEffect(() => {
        console.log(&#39;对输入框值更新的响应-----&#39; + value + &#39;-------------&#39;)
        if (type === 1) {
            setSearchVal(value || &#39;-&#39;)
        }
        if (type === 2) {
            startTransition(() => {
                setSearchVal(value || &#39;-&#39;)
            })
       }
    }, [value, type]);

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

普通模式下

淺析react18中的新概念Transition

#如圖:連續輸入字元123,當第一個字元輸入後,搜尋值馬上回應,清單渲染立刻開始,造成卡頓輸入框停止了對使用者輸入的回應,直到渲染結束,輸入框才繼續回應。

使用startTransition後

淺析react18中的新概念Transition

#如圖所示:連續輸入字元123,輸入框不斷回應,搜尋值的回應被延後,保證頁面回饋,直到輸入結束,才開始回應搜尋值,渲染搜尋結果,保持頁面回應。

4. useTransiton

#useTransiton使用介紹

import { useTransiton } from &#39;react&#39;

const [isPending, startTransition] = useTransiton({timeoutMs: 2000})
// 例如, 在pending状态下,您可以展示一个Spinner
{ isPending ? < Spinner /> : null }

  • #startTransition 是一個接受回呼的函數,用來告知React需要延遲更新的state。
  • isPending 是一個布林值,這是react告知我們是否等待過渡完成的方式。
  • useTransition 接受帶有 timeoutMs 的延遲回應的值,如果給定的timeoutMs內未完成,它將會強制執行startTransition回呼函數內state的更新。

useTransiton簡單分析

我們透過偽代碼理解下

useTransition

function useTransition(){
    const [isPending, setPending] = mountState(false);
    const start = (callback)=>{
        setPending(true);
        // Scheduler.unstable_next 通过 transiton 模式,低优先级调度执行回调函数
        // 可以降低更新的优先级。如果回调中触发的更新优先级会比较低,
        // 它会让位为高优先级的更新,或者当前事务繁忙时,调度到下一空闲期再应用。
        Scheduler.unstable_next(() => {
            const prevTransition = ReactCurrentBatchConfig.transition;
            ReactCurrentBatchConfig.transition = 1;
            try {
                setPending(false);
                //实行回调函数
                callback();
            } finally {
                ReactCurrentBatchConfig.transition = prevTransition;
            }
        })
    }
    return [isPending, start];
}

startTransition执行过程中,会触发两次setPending ,一次在transition=1之前,一次在之后。startTransition被调用时setPending(true),当startTransition内部的回调函数执行时transiton过渡任务更新setPending(false)。react内部可以根据pending值的变化准确把握等待的过渡时间,并依此判断是否超过了timeoutMs(如果有传入)强制执行更新。

5. useDeferredValue

useDeferredValue使用介绍

const [value, setValue] = useState(&#39;&#39;)
// defferedValue值延后于state更新
const deferredValue = useDeferredValue(value, {timeoutMs: 2000})
  • useDeferredValue 返回一个延迟响应的状态,可以设置最长延迟时间timeoutMs
  • 可以传入可选的timeoutMs,如果给定的timeoutMs内未完成,它将会强制更新。
  • 与useTransition的不同: useTransition是处理一段逻辑,而useDeferred是产生一个新状态

useDeferredValue的使用

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

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

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

    useEffect(() => {
        console.log(&#39;对输入框值的响应--------&#39; + value + &#39;---------------&#39;)
    }, [value])

    useEffect(() => {
        // 监听搜索值改变
        console.log(&#39;对搜索值的更新响应++++++&#39; + searchValue + &#39;+++++++++++&#39;)
    }, [searchValue])

    return (
        <div className=&#39;App&#39;>
            <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>
    );
};

淺析react18中的新概念Transition

useDeferredValue简单分析

我们通过伪代码理解下useDeferredValue

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

useDeferredValue通过useEffect监听传入值的变化,然后通过过渡任务执行值的改变。这样保证defrredValue的更新滞后于setState,同时符合过渡更新的原则,因为是通过transition 调度机制执行的。

更多编程相关知识,请访问:编程视频!!

以上是淺析react18中的新概念Transition的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除