Eesti

Sügav ülevaade Reacti useDeferredValue hook'ist. Õpi parandama kasutajaliidese viivitusi, mõistma samaaegsust, võrdlema useTransition'iga ja looma kiiremaid rakendusi.

Reacti useDeferredValue: Lõplik juhend mitteblokeeriva kasutajaliidese jõudluse kohta

Tänapäevases veebiarenduse maailmas on kasutajakogemus esmatähtis. Kiire ja reageeriv kasutajaliides ei ole enam luksus – see on ootus. Kasutajate jaoks üle maailma, laias valikus seadmetes ja võrgutingimustes, võib aeglane ja hakiline kasutajaliides olla vahe tagasipöörduva ja kaotatud kliendi vahel. Siin muudavad React 18 samaaegsuse funktsioonid, eriti useDeferredValue hook, mängu.

Kui olete kunagi loonud Reacti rakenduse otsinguväljaga, mis filtreerib suurt nimekirja, andmetabeli, mis uueneb reaalajas, või keerulise armatuurlaua, olete tõenäoliselt kokku puutunud kardetud kasutajaliidese külmumisega. Kasutaja trükib ja sekundi murdosa jooksul muutub kogu rakendus reageerimisvõimetuks. See juhtub seetõttu, et traditsiooniline renderdamine Reactis on blokeeriv. Oleku värskendus käivitab uuesti renderdamise ja midagi muud ei saa juhtuda enne, kui see on lõppenud.

See põhjalik juhend viib teid sügavale useDeferredValue hook'i maailma. Uurime probleemi, mida see lahendab, kuidas see Reacti uue samaaegsuse mootoriga kapoti all töötab ja kuidas saate seda kasutada uskumatult reageerimisvõimeliste rakenduste loomiseks, mis tunduvad kiired, isegi kui nad teevad palju tööd. Käsitleme praktilisi näiteid, täpsemaid mustreid ja olulisi parimaid tavasid globaalsele publikule.

Põhiprobleemi mõistmine: blokeeriv kasutajaliides

Enne kui saame lahendust hinnata, peame probleemi täielikult mõistma. Enne React 18 versioone oli renderdamine sünkroonne ja katkematu protsess. Kujutage ette üherealist teed: kui auto (renderdamine) siseneb, ei saa ükski teine auto mööduda enne, kui see on jõudnud lõppu. Nii töötas React.

Vaatleme klassikalist stsenaariumi: otsitav toodete nimekiri. Kasutaja trükib otsingukasti ja tuhandete toodete nimekiri allpool filtreeritakse nende sisendi põhjal.

Tüüpiline (ja aeglane) implementatsioon

Siin on, kuidas kood võiks välja näha enne React 18 või ilma samaaegsuse funktsioone kasutamata:

Komponendi struktuur:

Fail: SearchPage.js

import React, { useState } from 'react'; import ProductList from './ProductList'; import { generateProducts } from './data'; // funktsioon, mis loob suure massiivi const allProducts = generateProducts(20000); // Kujutame ette 20 000 toodet 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;

Miks see on aeglane?

Jälgime kasutaja tegevust:

  1. Kasutaja sisestab tähe, näiteks 'a'.
  2. onChange sündmus käivitub, kutsudes välja handleChange.
  3. setQuery('a') kutsutakse välja. See planeerib SearchPage komponendi uuesti renderdamise.
  4. React alustab uuesti renderdamist.
  5. Renderdamise sees käivitatakse rida const filteredProducts = allProducts.filter(...). See on kallis osa. 20 000 elemendiga massiivi filtreerimine, isegi lihtsa 'includes' kontrolliga, võtab aega.
  6. Sel ajal, kui see filtreerimine toimub, on brauseri põhilõim täielikult hõivatud. See ei saa töödelda uut kasutaja sisendit, ei saa visuaalselt uuendada sisendvälja ega käivitada muud JavaScripti. Kasutajaliides on blokeeritud.
  7. Kui filtreerimine on lõppenud, jätkab React ProductList komponendi renderdamist, mis iseenesest võib olla raske operatsioon, kui see renderdab tuhandeid DOM-sõlmi.
  8. Lõpuks, pärast kogu seda tööd, uuendatakse DOM-i. Kasutaja näeb tähte 'a' sisestuskastis ja nimekiri uueneb.

Kui kasutaja sisestab kiiresti – näiteks "õun" – toimub kogu see blokeeriv protsess 'õ', seejärel 'õu', siis 'õun', 'õuna' ja 'õun'. Tulemuseks on märgatav viivitus, kus sisendväli kokutab ja püüab kasutaja trükkimisega sammu pidada. See on halb kasutajakogemus, eriti vähem võimsates seadmetes, mis on levinud paljudes maailma osades.

Sissejuhatus React 18 samaaegsusse

React 18 muudab seda paradigmat põhjalikult, tuues sisse samaaegsuse. Samaaegsus ei ole sama mis paralleelsus (mitme asja tegemine samal ajal). Selle asemel on see Reacti võime renderdamist peatada, jätkata või hüljata. Üherealisel teel on nüüd möödasõidurajad ja liiklusreguleerija.

Samaaegsusega saab React liigitada uuendused kahte tüüpi:

React saab nüüd alustada mitte-kiireloomulist "ülemineku" renderdamist ja kui sisse tuleb kiireloomulisem uuendus (nagu järgmine klahvivajutus), saab see pikaajalise renderdamise peatada, tegeleda esmalt kiireloomulisega ja seejärel oma tööd jätkata. See tagab, et kasutajaliides jääb alati interaktiivseks. useDeferredValue hook on peamine tööriist selle uue võimsuse ärakasutamiseks.

Mis on `useDeferredValue`? Detailne selgitus

Oma olemuselt on useDeferredValue hook, mis laseb teil Reactile öelda, et teatud väärtus teie komponendis ei ole kiireloomuline. See aktsepteerib väärtust ja tagastab selle väärtuse uue koopia, mis "jääb maha", kui toimuvad kiireloomulised uuendused.

Süntaks

Hook'i kasutamine on uskumatult lihtne:

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

See ongi kõik. Annate sellele väärtuse ja see tagastab teile selle väärtuse edasilükatud versiooni.

Kuidas see kapoti all töötab

Teeme selle maagia selgeks. Kui kasutate useDeferredValue(query), teeb React järgmist:

  1. Esimene renderdamine: Esimesel renderdamisel on deferredQuery sama, mis algne query.
  2. Toimub kiireloomuline uuendus: Kasutaja sisestab uue tähe. query olek uueneb 'a'-st 'ap'-ks.
  3. Kõrge prioriteediga renderdamine: React käivitab kohe uuesti renderdamise. Selle esimese, kiireloomulise uuesti renderdamise ajal teab useDeferredValue, et käimas on kiireloomuline uuendus. Seega tagastab see endiselt eelmise väärtuse, 'a'. Teie komponent renderdatakse kiiresti uuesti, sest sisendvälja väärtus muutub 'ap'-ks (olekust), kuid teie kasutajaliidese osa, mis sõltub deferredQuery-st (aeglane nimekiri), kasutab endiselt vana väärtust ja seda ei pea uuesti arvutama. Kasutajaliides jääb reageerimisvõimeliseks.
  4. Madala prioriteediga renderdamine: Kohe pärast kiireloomulise renderdamise lõppu alustab React teist, mitte-kiireloomulist renderdamist taustal. *Selles* renderdamises tagastab useDeferredValue uue väärtuse, 'ap'. See taustal renderdamine käivitab kalli filtreerimisoperatsiooni.
  5. Katkestatavus: Siin on võtmeosa. Kui kasutaja trükib veel ühe tähe ('app'), samal ajal kui madala prioriteediga renderdamine 'ap' jaoks on veel pooleli, viskab React selle taustal renderdamise ära ja alustab uuesti. See eelistab uut kiireloomulist uuendust ('app') ja seejärel planeerib uue taustal renderdamise uusima edasilükatud väärtusega.

See tagab, et kallis töö tehakse alati kõige värskemate andmetega ja see ei blokeeri kunagi kasutajal uue sisendi andmist. See on võimas viis raskete arvutuste deprioritiseerimiseks ilma keerulise käsitsi viivitamise (debouncing) või piiramise (throttling) loogikata.

Praktiline implementatsioon: meie aeglase otsingu parandamine

Refaktoreerime meie eelmise näite, kasutades useDeferredValue, et näha seda töös.

Fail: SearchPage.js (optimeeritud)

import React, { useState, useDeferredValue, useMemo } from 'react'; import ProductList from './ProductList'; import { generateProducts } from './data'; const allProducts = generateProducts(20000); // Komponent nimekirja kuvamiseks, jõudluse huvides memoiseeritud const MemoizedProductList = React.memo(ProductList); function SearchPage() { const [query, setQuery] = useState(''); // 1. Lükka query väärtus edasi. See väärtus jääb 'query' olekust maha. const deferredQuery = useDeferredValue(query); // 2. Kallis filtreerimine on nüüd juhitud deferredQuery poolt. // Lisaks mähime selle edasiseks optimeerimiseks useMemo sisse. const filteredProducts = useMemo(() => { console.log('Filtreerin:', deferredQuery); return allProducts.filter(product => { return product.name.toLowerCase().includes(deferredQuery.toLowerCase()); }); }, [deferredQuery]); // Arvutab uuesti ainult siis, kui deferredQuery muutub function handleChange(e) { // See oleku värskendus on kiireloomuline ja töödeldakse kohe setQuery(e.target.value); } return (

{/* 3. Sisendit kontrollib kõrge prioriteediga 'query' olek. See tundub kohene. */} {/* 4. Nimekiri renderdatakse edasilükatud, madala prioriteediga uuenduse tulemusena. */}
); } export default SearchPage;

Muutus kasutajakogemuses

Selle lihtsa muudatusega on kasutajakogemus muutunud:

Rakendus tundub nüüd oluliselt kiirem ja professionaalsem.

`useDeferredValue` vs. `useTransition`: Mis on erinevus?

See on üks levinumaid segaduse tekitajaid arendajatele, kes õpivad samaaegset Reacti. Nii useDeferredValue kui ka useTransition kasutatakse uuenduste mitte-kiireloomuliseks märkimiseks, kuid neid rakendatakse erinevates olukordades.

Võtmeerinevus on: kus teil on kontroll?

`useTransition`

Kasutate useTransition'i, kui teil on kontroll koodi üle, mis käivitab oleku uuenduse. See annab teile funktsiooni, tavaliselt nimega startTransition, millega saate oma oleku uuenduse ümbritseda.

const [isPending, startTransition] = useTransition(); function handleChange(e) { const nextValue = e.target.value; // Uuenda kiireloomuline osa kohe setInputValue(nextValue); // Mässi aeglane uuendus startTransition'i sisse startTransition(() => { setSearchQuery(nextValue); }); }

`useDeferredValue`

Kasutate useDeferredValue'd, kui te ei kontrolli koodi, mis väärtust uuendab. See juhtub sageli siis, kui väärtus tuleb props'idest, vanemkomponendist või mõnest muust hook'ist, mille pakub kolmanda osapoole teek.

function SlowList({ valueFromParent }) { // Me ei kontrolli, kuidas valueFromParent on seatud. // Me lihtsalt saame selle ja tahame selle põhjal renderdamist edasi lükata. const deferredValue = useDeferredValue(valueFromParent); // ... kasuta deferredValue'd komponendi aeglase osa renderdamiseks }

Võrdluse kokkuvõte

Omadus `useTransition` `useDeferredValue`
Mida see ümbritseb Oleku uuendamise funktsiooni (nt startTransition(() => setState(...))) Väärtust (nt useDeferredValue(myValue))
Kontrollpunkt Kui kontrollite sündmuse käsitlejat või uuenduse käivitajat. Kui saate väärtuse (nt props'idest) ja teil pole kontrolli selle allika üle.
Laadimise olek Pakub sisseehitatud `isPending` boolean'i. Sisseehitatud lippu pole, kuid saab tuletada `const isStale = originalValue !== deferredValue;` abil.
Analoogia Olete dispetšer, kes otsustab, milline rong (oleku uuendus) lahkub aeglasel rajal. Olete jaamaülem, kes näeb rongiga saabuvat väärtust ja otsustab seda hetkeks jaamas hoida, enne kui kuvab selle peatahvlil.

Täpsemad kasutusjuhud ja mustrid

Lisaks lihtsale nimekirja filtreerimisele avab useDeferredValue mitu võimsat mustrit keerukate kasutajaliideste ehitamiseks.

Muster 1: "Aegunud" kasutajaliidese näitamine tagasisidena

Kasutajaliides, mis uueneb kerge viivitusega ilma visuaalse tagasisideta, võib kasutajale tunduda vigane. Nad võivad mõelda, kas nende sisend registreeriti. Suurepärane muster on anda peen vihje, et andmed uuenevad.

Seda saate saavutada, võrreldes algset väärtust edasilükatud väärtusega. Kui need on erinevad, tähendab see, et taustal on ootel renderdamine.

function SearchPage() { const [query, setQuery] = useState(''); const deferredQuery = useDeferredValue(query); // See boolean ütleb meile, kas nimekiri jääb sisendist maha const isStale = query !== deferredQuery; const filteredProducts = useMemo(() => { // ... kallis filtreerimine deferredQuery abil }, [deferredQuery]); return (

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

Selles näites muutub isStale tõeseks kohe, kui kasutaja trükib. Nimekiri muutub veidi läbipaistvamaks, andes märku, et see hakkab kohe uuendama. Kui edasilükatud renderdamine on lõppenud, muutuvad query ja deferredQuery uuesti võrdseks, isStale muutub vääraks ja nimekiri taastab täieliku läbipaistvuse uute andmetega. See on samaväärne isPending lipuga useTransition'ist.

Muster 2: Diagrammide ja visualiseeringute uuenduste edasilükkamine

Kujutage ette keerukat andmete visualiseerimist, nagu geograafiline kaart või finantsdiagramm, mis renderdatakse uuesti kasutaja poolt kontrollitava kuupäevavahemiku liuguri põhjal. Liuguri lohistamine võib olla äärmiselt hakiline, kui diagramm renderdatakse uuesti iga liikumispiksli peale.

Lükates liuguri väärtust edasi, saate tagada, et liuguri käepide ise jääb sujuvaks ja reageerivaks, samal ajal kui raske diagrammikomponent renderdatakse sujuvalt taustal.

function ChartDashboard() { const [year, setYear] = useState(2023); const deferredYear = useDeferredValue(year); // HeavyChart on memoiseeritud komponent, mis teeb kalleid arvutusi // See renderdatakse uuesti ainult siis, kui deferredYear väärtus stabiliseerub. const chartData = useMemo(() => computeChartData(deferredYear), [deferredYear]); return (

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

Parimad praktikad ja levinumad lõksud

Kuigi võimas, tuleks useDeferredValue'd kasutada kaalutletult. Siin on mõned peamised parimad tavad, mida järgida:

Mõju globaalsele kasutajakogemusele (UX)

Tööriistade nagu useDeferredValue kasutuselevõtt ei ole ainult tehniline optimeerimine; see on pühendumine paremale ja kaasavamale kasutajakogemusele globaalsele publikule.

Kokkuvõte

Reacti useDeferredValue hook on paradigma muutus selles, kuidas me läheneme jõudluse optimeerimisele. Selle asemel, et tugineda käsitsi ja sageli keerukatele tehnikatele nagu viivitamine (debouncing) ja piiramine (throttling), saame nüüd deklaratiivselt öelda Reactile, millised meie kasutajaliidese osad on vähem kriitilised, võimaldades tal planeerida renderdamistööd palju intelligentsemal ja kasutajasõbralikumal viisil.

Mõistes samaaegsuse põhiprintsiipe, teades, millal kasutada useDeferredValue'd versus useTransition'i, ja rakendades parimaid tavasid nagu memoiseerimine ja kasutajate tagasiside, saate kõrvaldada kasutajaliidese hakkimise ja luua rakendusi, mis pole mitte ainult funktsionaalsed, vaid ka meeldivad kasutada. Konkurentsitihedal globaalsel turul on kiire, reageeriva ja ligipääsetava kasutajakogemuse pakkumine ülim funktsioon ning useDeferredValue on üks võimsamaid tööriistu teie arsenalis selle saavutamiseks.