Lietuvių

Išsami React „useDeferredValue“ kabliuko analizė. Sužinokite, kaip išspręsti vartotojo sąsajos vėlavimą, suprasti konkurencingumą, palyginti su „useTransition“ ir kurti greitesnes programas pasaulinei auditorijai.

React „useDeferredValue“: Išsamus vadovas apie neblokuojantį vartotojo sąsajos našumą

Šiuolaikiniame žiniatinklio kūrimo pasaulyje vartotojo patirtis yra svarbiausia. Greita, reaguojanti sąsaja nebėra prabanga – tai lūkestis. Vartotojams visame pasaulyje, naudojantiems įvairiausius įrenginius ir esant skirtingoms tinklo sąlygoms, vėluojanti, stringanti vartotojo sąsaja gali nulemti, ar klientas sugrįš, ar bus prarastas. Būtent čia „React 18“ konkurentiškumo funkcijos, ypač useDeferredValue kabliukas, keičia žaidimo taisykles.

Jei kada nors kūrėte „React“ programą su paieškos laukeliu, kuris filtruoja didelį sąrašą, duomenų tinkleliu, kuris atsinaujina realiu laiku, ar sudėtingu prietaisų skydeliu, tikriausiai susidūrėte su bauginančiu vartotojo sąsajos užšalimu. Vartotojas rašo, ir sekundės dalį visa programa nustoja reaguoti. Taip nutinka, nes tradicinis atvaizdavimas „React“ yra blokuojantis. Būsenos atnaujinimas sukelia pervaizdavimą, ir niekas kitas negali įvykti, kol jis nebus baigtas.

Šis išsamus vadovas leis jums nuodugniai susipažinti su useDeferredValue kabliuku. Išnagrinėsime, kokią problemą jis sprendžia, kaip jis veikia „React“ naujojo konkurentiško variklio viduje ir kaip galite jį panaudoti kurdami neįtikėtinai reaguojančias programas, kurios atrodo greitos, net kai atlieka daug darbo. Aptarsime praktinius pavyzdžius, pažangius šablonus ir svarbiausias geriausias praktikas pasaulinei auditorijai.

Pagrindinės problemos supratimas: blokuojanti vartotojo sąsaja

Prieš įvertindami sprendimą, turime visiškai suprasti problemą. Ankstesnėse nei 18 „React“ versijose atvaizdavimas buvo sinchroniškas ir nepertraukiamas procesas. Įsivaizduokite vienos eismo juostos kelią: kai įvažiuoja automobilis (atvaizdavimas), joks kitas automobilis negali pravažiuoti, kol pirmasis nepasieks galo. Taip veikė „React“.

Panagrinėkime klasikinį scenarijų: produktų sąrašas su paieška. Vartotojas rašo tekstą paieškos laukelyje, o žemiau esantis tūkstančių elementų sąrašas filtruojamas pagal jo įvestį.

Tipiškas (ir lėtas) įgyvendinimas

Štai kaip kodas galėtų atrodyti „pre-React 18“ pasaulyje arba nenaudojant konkurentiškumo funkcijų:

Komponento struktūra:

Failas: SearchPage.js

import React, { useState } from 'react'; import ProductList from './ProductList'; import { generateProducts } from './data'; // funkcija, kuri sukuria didelį masyvą const allProducts = generateProducts(20000); // Įsivaizduokime 20 000 produktų function SearchPage() { const [query, setQuery] = useState(''); const filteredProducts = allProducts.filter(product => { return product.name.toLowerCase().includes(query.toLowerCase()); }); function handleChange(e) { setQuery(e.target.value); } return (

); } export default SearchPage;

Kodėl tai veikia lėtai?

Panagrinėkime vartotojo veiksmą:

  1. Vartotojas įveda raidę, tarkime, „a“.
  2. Suveikia onChange įvykis, iškviesdamas handleChange.
  3. Iškviečiama setQuery('a'). Tai suplanuoja SearchPage komponento pervaizdavimą.
  4. „React“ pradeda pervaizdavimą.
  5. Pervaizdavimo metu įvykdoma eilutė const filteredProducts = allProducts.filter(...). Tai yra brangioji dalis. Filtruoti 20 000 elementų masyvą, net ir su paprastu „includes“ patikrinimu, užtrunka.
  6. Kol vyksta šis filtravimas, naršyklės pagrindinė gija yra visiškai užimta. Ji negali apdoroti jokios naujos vartotojo įvesties, negali vizualiai atnaujinti įvesties lauko ir negali vykdyti jokio kito „JavaScript“ kodo. Vartotojo sąsaja yra blokuota.
  7. Kai filtravimas baigtas, „React“ pereina prie ProductList komponento atvaizdavimo, kas savaime gali būti sunki operacija, jei atvaizduojama tūkstančiai DOM mazgų.
  8. Galiausiai, po viso šio darbo, DOM yra atnaujinamas. Vartotojas mato, kad įvesties laukelyje atsiranda raidė „a“, o sąrašas atsinaujina.

Jei vartotojas rašo greitai – tarkime, „obuolys“ – visas šis blokavimo procesas vyksta su „o“, tada „ob“, „obu“, „obuo“, „obuol“ ir „obuolys“. Rezultatas – pastebimas vėlavimas, kai įvesties laukas stringa ir stengiasi neatsilikti nuo vartotojo rašymo. Tai prasta vartotojo patirtis, ypač mažiau galinguose įrenginiuose, kurie yra paplitę daugelyje pasaulio šalių.

Pristatome „React 18“ konkurencingumą

„React 18“ iš esmės keičia šią paradigmą, įvesdama konkurencingumą. Konkurencingumas nėra tas pats, kas lygiagretumas (daryti kelis dalykus tuo pačiu metu). Vietoj to, tai yra „React“ gebėjimas sustabdyti, atnaujinti arba nutraukti atvaizdavimą. Vienos eismo juostos kelias dabar turi lenkimo juostas ir eismo reguliuotoją.

Su konkurencingumu „React“ gali suskirstyti atnaujinimus į du tipus:

Dabar „React“ gali pradėti neskubų „perėjimo“ atvaizdavimą, ir jei atsiranda skubesnis atnaujinimas (pavyzdžiui, kitas klavišo paspaudimas), jis gali sustabdyti ilgai trunkantį atvaizdavimą, pirmiausia apdoroti skubųjį, o tada tęsti savo darbą. Tai užtikrina, kad vartotojo sąsaja visada išliktų interaktyvi. useDeferredValue kabliukas yra pagrindinis įrankis šiai naujai galiai išnaudoti.

Kas yra `useDeferredValue`? Išsamus paaiškinimas

Iš esmės, useDeferredValue yra kabliukas, kuris leidžia jums pasakyti „React“, kad tam tikra reikšmė jūsų komponente nėra skubi. Jis priima reikšmę ir grąžina naują tos reikšmės kopiją, kuri „atsiliks“, jei vyksta skubūs atnaujinimai.

Sintaksė

Šį kabliuką naudoti yra neįtikėtinai paprasta:

import { useDeferredValue } from 'react'; const deferredValue = useDeferredValue(value);

Viskas. Jūs perduodate jam reikšmę, ir jis grąžina jums atidėtą tos reikšmės versiją.

Kaip tai veikia viduje

Išsklaidykime magiją. Kai naudojate useDeferredValue(query), štai ką daro „React“:

  1. Pradinis atvaizdavimas: Pirmojo atvaizdavimo metu deferredQuery bus toks pat kaip pradinis query.
  2. Įvyksta skubus atnaujinimas: Vartotojas įveda naują simbolį. query būsena pasikeičia iš „a“ į „ap“.
  3. Aukšto prioriteto atvaizdavimas: „React“ nedelsiant sukelia pervaizdavimą. Per šį pirmąjį, skubų pervaizdavimą, useDeferredValue žino, kad vyksta skubus atnaujinimas. Todėl jis vis dar grąžina ankstesnę reikšmę, „a“. Jūsų komponentas greitai pervaizduojamas, nes įvesties lauko reikšmė tampa „ap“ (iš būsenos), bet ta jūsų vartotojo sąsajos dalis, kuri priklauso nuo deferredQuery (lėtas sąrašas), vis dar naudoja seną reikšmę ir jos nereikia perskaičiuoti. Vartotojo sąsaja išlieka reaguojanti.
  4. Žemo prioriteto atvaizdavimas: Iškart po to, kai baigiasi skubus atvaizdavimas, „React“ fone pradeda antrą, neskubų pervaizdavimą. *Šiame* atvaizdavime useDeferredValue grąžina naują reikšmę, „ap“. Šis foninis atvaizdavimas sukelia brangią filtravimo operaciją.
  5. Pertraukiamumas: Štai svarbiausia dalis. Jei vartotojas įveda kitą raidę („app“), kol žemo prioriteto atvaizdavimas „ap“ vis dar vyksta, „React“ atmes tą foninį atvaizdavimą ir pradės iš naujo. Jis teikia pirmenybę naujam skubiam atnaujinimui („app“), o tada suplanuoja naują foninį atvaizdavimą su naujausia atidėta reikšme.

Tai užtikrina, kad brangus darbas visada atliekamas su naujausiais duomenimis ir niekada neblokuoja vartotojo nuo naujos įvesties. Tai galingas būdas sumažinti sunkių skaičiavimų prioritetą be sudėtingos rankinės „debouncing“ ar „throttling“ logikos.

Praktinis įgyvendinimas: lėtos paieškos pataisymas

Pakeiskime ankstesnį pavyzdį naudodami useDeferredValue, kad pamatytume jį veikiant.

Failas: SearchPage.js (Optimizuotas)

import React, { useState, useDeferredValue, useMemo } from 'react'; import ProductList from './ProductList'; import { generateProducts } from './data'; const allProducts = generateProducts(20000); // Komponentas sąrašui rodyti, memoizuotas našumui const MemoizedProductList = React.memo(ProductList); function SearchPage() { const [query, setQuery] = useState(''); // 1. Atidėkite užklausos reikšmę. Ši reikšmė atsiliks nuo „query“ būsenos. const deferredQuery = useDeferredValue(query); // 2. Brangus filtravimas dabar priklauso nuo deferredQuery. // Mes taip pat apgaubiame tai useMemo tolimesniam optimizavimui. const filteredProducts = useMemo(() => { console.log('Filtruojama pagal:', deferredQuery); return allProducts.filter(product => { return product.name.toLowerCase().includes(deferredQuery.toLowerCase()); }); }, [deferredQuery]); // Perskaičiuojama tik pasikeitus deferredQuery function handleChange(e) { // Šis būsenos atnaujinimas yra skubus ir bus apdorotas nedelsiant setQuery(e.target.value); } return (

{/* 3. Įvesties laukas valdomas aukšto prioriteto „query“ būsenos. Jis veikia akimirksniu. */} {/* 4. Sąrašas atvaizduojamas naudojant atidėto, žemo prioriteto atnaujinimo rezultatą. */}
); } export default SearchPage;

Vartotojo patirties transformacija

Su šiuo paprastu pakeitimu vartotojo patirtis transformuojasi:

Dabar programa jaučiasi žymiai greitesnė ir profesionalesnė.

`useDeferredValue` ir `useTransition` palyginimas: koks skirtumas?

Tai yra vienas iš dažniausiai pasitaikančių painiavos taškų programuotojams, besimokantiems konkurentiško „React“. Tiek useDeferredValue, tiek useTransition yra naudojami atnaujinimams pažymėti kaip neskubiems, tačiau jie taikomi skirtingose situacijose.

Pagrindinis skirtumas yra: kur jūs turite kontrolę?

`useTransition`

useTransition naudojate, kai turite kontrolę ties kodu, kuris sukelia būsenos atnaujinimą. Jis suteikia jums funkciją, paprastai vadinamą startTransition, kuria galite apgaubti savo būsenos atnaujinimą.

const [isPending, startTransition] = useTransition(); function handleChange(e) { const nextValue = e.target.value; // Nedelsiant atnaujinkite skubiąją dalį setInputValue(nextValue); // Apgaubkite lėtą atnaujinimą startTransition startTransition(() => { setSearchQuery(nextValue); }); }

`useDeferredValue`

useDeferredValue naudojate, kai nekontroliuojate kodo, kuris atnaujina reikšmę. Tai dažnai nutinka, kai reikšmė ateina iš „props“, iš tėvinio komponento ar iš kito kabliuko, kurį teikia trečiosios šalies biblioteka.

function SlowList({ valueFromParent }) { // Mes nekontroliuojame, kaip nustatoma valueFromParent. // Mes tiesiog gauname ją ir norime atidėti atvaizdavimą remdamiesi ja. const deferredValue = useDeferredValue(valueFromParent); // ... naudokite deferredValue lėtajai komponento daliai atvaizduoti }

Palyginimo suvestinė

Savybė `useTransition` `useDeferredValue`
Ką apgaubia Būsenos atnaujinimo funkciją (pvz., startTransition(() => setState(...))) Reikšmę (pvz., useDeferredValue(myValue))
Kontrolės taškas Kai kontroliuojate įvykio apdorojimo funkciją arba atnaujinimo paleidiklį. Kai gaunate reikšmę (pvz., iš „props“) ir neturite kontrolės jos šaltiniui.
Įkėlimo būsena Suteikia integruotą `isPending` loginę reikšmę. Nėra integruotos vėliavėlės, bet galima ją išvesti su `const isStale = originalValue !== deferredValue;`.
Analogija Jūs esate dispečeris, sprendžiantis, kuris traukinys (būsenos atnaujinimas) išvyks lėtuoju bėgiu. Jūs esate stoties viršininkas, matantis traukiniu atvykstančią reikšmę ir nusprendžiantis ją trumpam palaikyti stotyje, prieš parodydamas pagrindinėje lentoje.

Pažangūs naudojimo atvejai ir šablonai

Be paprasto sąrašų filtravimo, useDeferredValue atveria keletą galingų šablonų sudėtingoms vartotojo sąsajoms kurti.

1 šablonas: „pasenusios“ vartotojo sąsajos rodymas kaip grįžtamasis ryšys

Vartotojo sąsaja, kuri atsinaujina su nedideliu vėlavimu be jokio vizualinio grįžtamojo ryšio, vartotojui gali atrodyti klaidinga. Jie gali susimąstyti, ar jų įvestis buvo užregistruota. Puikus šablonas yra pateikti subtilų ženklą, kad duomenys atsinaujina.

Tai galite pasiekti palygindami pradinę reikšmę su atidėta reikšme. Jei jos skiriasi, tai reiškia, kad laukiamas foninis atvaizdavimas.

function SearchPage() { const [query, setQuery] = useState(''); const deferredQuery = useDeferredValue(query); // Ši loginė reikšmė parodo, ar sąrašas atsilieka nuo įvesties const isStale = query !== deferredQuery; const filteredProducts = useMemo(() => { // ... brangus filtravimas naudojant deferredQuery }, [deferredQuery]); return (

setQuery(e.target.value)} />
); }

Šiame pavyzdyje, kai tik vartotojas pradeda rašyti, isStale tampa „true“. Sąrašas šiek tiek išblunka, nurodydamas, kad netrukus atsinaujins. Kai atidėtas atvaizdavimas baigiasi, query ir deferredQuery vėl tampa lygūs, isStale tampa „false“, o sąrašas grįžta į pilną ryškumą su naujais duomenimis. Tai yra isPending vėliavėlės iš useTransition atitikmuo.

2 šablonas: atnaujinimų atidėjimas diagramose ir vizualizacijose

Įsivaizduokite sudėtingą duomenų vizualizaciją, pavyzdžiui, geografinį žemėlapį ar finansinę diagramą, kuri persipiešia remdamasi vartotojo valdomu slankikliu datos diapazonui. Slankiklio vilkimas gali būti labai trūkčiojantis, jei diagrama persipiešia su kiekvienu judesio pikseliu.

Atidėdami slankiklio reikšmę, galite užtikrinti, kad pati slankiklio rankenėlė išliks sklandi ir reaguojanti, o sunki diagrama grakščiai persipieš fone.

function ChartDashboard() { const [year, setYear] = useState(2023); const deferredYear = useDeferredValue(year); // HeavyChart yra memoizuotas komponentas, atliekantis brangius skaičiavimus // Jis persipieš tik tada, kai deferredYear reikšmė nusistovės. const chartData = useMemo(() => computeChartData(deferredYear), [deferredYear]); return (

setYear(parseInt(e.target.value, 10))} /> Pasirinkti metai: {year}
); }

Geriausios praktikos ir dažniausios klaidos

Nors useDeferredValue yra galingas, jį reikėtų naudoti apgalvotai. Štai keletas pagrindinių geriausių praktikų, kurių reikėtų laikytis:

Poveikis pasaulinei vartotojo patirčiai (UX)

Tokių įrankių kaip useDeferredValue pritaikymas yra ne tik techninis optimizavimas; tai įsipareigojimas geresnei, labiau įtraukiančiai vartotojo patirčiai pasaulinei auditorijai.

Išvada

React useDeferredValue kabliukas yra paradigmų kaita, kaip mes prieiname prie našumo optimizavimo. Užuot pasikliovę rankiniais ir dažnai sudėtingais metodais, tokiais kaip „debouncing“ ir „throttling“, dabar galime deklaratyviai nurodyti „React“, kurios mūsų vartotojo sąsajos dalys yra mažiau svarbios, leisdami jam daug protingiau ir vartotojui draugiškiau planuoti atvaizdavimo darbus.

Suprasdami pagrindinius konkurencingumo principus, žinodami, kada naudoti useDeferredValue, o kada useTransition, ir taikydami geriausias praktikas, tokias kaip memoizavimas ir vartotojo grįžtamasis ryšys, galite pašalinti vartotojo sąsajos strigimą ir kurti programas, kurios yra ne tik funkcionalios, bet ir malonios naudoti. Konkurencingoje pasaulinėje rinkoje greita, reaguojanti ir prieinama vartotojo patirtis yra pagrindinė savybė, o useDeferredValue yra vienas galingiausių įrankių jūsų arsenale jai pasiekti.