Jak používat metody plánování JavaScriptu s háky React

Někdy můžete chtít provést funkci v určitou dobu později nebo v určeném intervalu. Tento jev se nazývá scheduling a function call .

JavaScript poskytuje dvě metody,

  • setInterval
  • nastavení časového limitu

Použití těchto metod plánování s reactJs je přímočarý. Abychom je mohli efektivně využít, musíme si být vědomi několika malých problémů. V tomto článku prozkoumáme použití setInterval a setTimeout metody s reactJS komponenty.

Vytvořme jednoduchý Real-time Counter a Task Scheduler k demonstraci použití.

Co je setInterval?

setInterval metoda nám umožňuje spouštět funkci periodicky. Funkce se spustí po určitém časovém intervalu a poté se v tomto intervalu nepřetržitě opakuje.

Zde jsme definovali interval 1 sekundy (1000 milisekund) pro spuštění funkce, která vytiskne některé protokoly v konzole prohlížeče.

const timerId = setInterval(() => {
  console.log('Someone Scheduled me to run every second');
}, 1000);

setInterval volání funkce vrací timerId který lze použít ke zrušení časovače pomocí clearInterval metoda. Zastaví všechna další volání funkce setInterval.

clearInterval(timerId).

Co je setTimeout?

setTimeout metoda nám umožňuje spustit funkci once po časovém intervalu. Zde jsme definovali funkci pro přihlášení něčeho do konzole prohlížeče po 2 sekundách.

const timerId = setTimeout(() => {
  console.log('Will be called after 2 seconds');
}, 2000);

Stejně jako setInterval, volání metody setTimeout také vrací timerId . Toto ID lze použít k zastavení časovače.

clearTimeout(timerId);

Počítadlo v reálném čase

Vytvořme real-time counter aplikaci, abyste pochopili použití setInterval metoda v aplikaci reakce. Počítadlo v reálném čase má přepínací tlačítko pro spuštění a zastavení počitadla. Hodnota čítače se zvyšuje o 1 na konci každé sekundy, když uživatel spustí čítač. Uživatel bude moci zastavit počítadlo nebo obnovit počítadlo z počáteční hodnoty, nuly.

Budeme používat některé z vestavěných háčků z React, ale totéž je možné také pomocí komponenty React Class.

Takto se komponenta chová,

Krok 1 :Začněme importem React a dva vestavěné háčky, useState a useEffect .

import React, { useState, useEffect} from "react";

Krok 2 :Budeme potřebovat dvě stavové proměnné. Nejprve sledujte přepínač start-stop u real-time a druhý pro counter sám. Pojďme je inicializovat pomocí useState háček.

Háček useState vrací pár. První je aktuální stav a druhá je funkce aktualizace. K přiřazení hodnot obvykle využíváme destrukci pole. Hodnotu počátečního stavu lze předat pomocí argumentu.

 const [realTime, setRealTime] = useState(false);
 const [counter, setCounter] = useState(0);

Krok 3 :Háček useEffect se používá ke zpracování jakéhokoli druhu vedlejších efektů, jako jsou změny hodnoty stavu, jakýkoli druh předplatného, ​​síťové požadavky atd. Vyžaduje dva argumenty, nejprve funkci, která bude vyvolána za běhu, a pole hodnot, které spustí háček.

Ve výchozím nastavení se spouští po dokončení každého vykreslování. Můžeme jej však spustit vždy, když se konkrétní hodnota změní, tím, že ji předáme jako druhý parametr. Můžeme jej také zajistit, aby se spustil pouze jednou, když jako druhý parametr předáme prázdné pole.

V tomto případě máme zájem spustit useEffect hák, když uživatel přepne tlačítko v reálném čase (pro spuštění a zastavení). Chceme začít interval, když realTime stavová proměnná je pravdivá a zruší/zastaví interval, když je hodnota stavové proměnné nepravda. Zde je návod, jak může vypadat struktura kódu,

useEffect(() => {
  let interval;
  if (realTime) {
    interval = setInterval(() => {
      console.log('In setInterval');
      // The logic of changing counter value to come soon.
    }, 1000);
  } else {
     clearInterval(interval);
  }
  return () => clearInterval(interval);
}, [realTime]);

Použili jsme setInterval metoda uvnitř useEffect Hook, což je ekvivalent componentDidMount metoda životního cyklu v komponentách třídy. V tomto okamžiku pouze vytiskne protokol na konci 1sekundového intervalu. Časovač vymazáváme ve dvou případech. Za prvé, když je hodnota realTime stavová proměnná je false a za druhé, komponenta je odpojena.

Krok 4 :Čas na zvýšení počítadla. Nejjednodušší způsob, jak toho dosáhnout, bude zavolat setCounter a nastavte inkrementovanou hodnotu čítače takto,

setCounter(counter => counter + 1);

Zde si ale uvědomme jednu důležitou věc. setInterval metoda je uzávěrka, takže když je naplánováno setInterval, použije hodnotu čítače přesně v ten okamžik v čase, což je počáteční hodnota 0. To nám dá pocit, že stav z useState hook se neaktualizuje uvnitř setInterval metoda.

Podívejte se na tento kód,

useEffect(() => {
  let interval;
  if (realTime) {
    interval = setInterval(() => {
      console.log('In setInterval', counter);
    }, 1000);
    setCounter(100);
  } else {
    clearInterval(interval);
  }
   return () => clearInterval(interval);
}, [realTime]);

console.log('In setInterval', counter); řádek zaznamená 0 i když jsme nastavili hodnotu čítače na 100 . Zde potřebujeme něco speciálního, co dokáže sledovat změněnou hodnotu stavové proměnné bez opětovného vykreslování komponenty. Máme pro to další háček s názvem useRef pro tento účel.

useRef je jako "krabice" nebo "kontejner", který může obsahovat měnitelnou hodnotu ve svém .current vlastnictví. Můžeme zmutovat ref přímo pomocí counter.current = 100 . Podívejte se na tento úžasný článek od Bhanu Teja Pachipulusu, kde se dozvíte o useRef háček podrobněji.

Dobře, takže jej musíme nejprve importovat spolu s ostatními háčky.

import React, { useState, useEffect, useRef } from "react";

Poté použijte useRef háček pro mutaci ref a vytvoření synchronizace,

const countRef = useRef(counter);
countRef.current = counter;

Poté použijte countRef.current namísto counter hodnota stavu uvnitř funkce předaná do setInterval metoda.

useEffect(() => {
  let interval;
  if (realTime) {
    interval = setInterval(() => {
      let currCount = countRef.current;
      setCounter(currCount => currCount + 1);
    }, 1000);
  } else {
      clearInterval(interval);
  }
 return () => clearInterval(interval);
}, [realTime]);

Nyní máme zaručeno, že budeme neustále dostávat aktualizovanou (aktuální) hodnotu počítadla.

Krok 5 :Dalším krokem je vytvoření dvou funkcí pro přepínání tlačítka start-stop a vynulování počítadla.

const manageRealTime = () => {
  setRealTime(!realTime);
}

const reset = () => {
  setCounter(0);
}

Krok 6 :Posledním krokem je vytvoření jeho renderovací části.

<div className={style.btnGrpSpacing}>
  <Button
    className={style.btnSpacing} 
    variant={realTime? 'danger' : 'success'} 
    onClick={() => manageRealTime()}>
      {realTime ? 'Stop Real-Time': 'Start Real-Time'}
  </Button>
  <Button 
    className={style.btnSpacing} 
    variant= 'info'
    onClick={() => reset()}>
      Reset Counter
  </Button>
</div>

<div className={style.radial}>
  <span>{counter}</span>
</div>

To je vše. Máme komponentu pracující v reálném čase pomocí setInterval a reagovat háčky (useState , useEffect a useRef ).

Plánovač úloh

Nyní vytvoříme další komponentu reakce nazvanou Task Scheduler který naplánuje úlohu zvýšení čítače o 1 po každých 2 sekundách. Tento plánovač neprovede nic, dokud uživatel neklikne na tlačítko pro opětovné naplánování nebo resetování počítadla.

Takto se komponenta chová,

Stejně jako setInterval použijeme metodu setTimeout metoda uvnitř useEffect háček. Po odpojení komponenty také vymažeme časovač.

useEffect(() => {
  const timer = setTimeout(() => {
    console.log('setTimeout called!');
  }, 1000);

  return () => clearTimeout(timer);
}, []);

Stejně jako setInterval je i setTimeout uzávěr. Budeme tedy čelit podobné situaci jako stavová proměnná counter nemusí odrážet aktuální hodnotu uvnitř metody setTimeout.

useEffect(() => {
  const timer = setTimeout(() => {
    console.log(counter);
  }, 2000);
  setCounter(100);
return () => clearTimeout(timer);
}, []);

Ve výše uvedeném případě zůstane hodnota čítače 0 i když jsme nastavili hodnotu na 100 .

Tento problém můžeme vyřešit podobně, jak jsme to viděli v předchozím příkladu. Použijte háček useRef .

useEffect(() => {
  const timerId = schedule();
  return () => clearTimeout(timerId);
}, []);

const schedule = () => {
  setScheduleMessage('Scheduled in 2s...');
    const timerId = setTimeout(() => {
      let currCount = countRef.current;
      setCounter(currCount => currCount + 1);
      console.log(counter);
  }, 2000);

   return timerId;
}

Zde předáváme funkci schedule na metodu setTimeout. schedule funkce využívá aktuální hodnotu z reference(ref) a podle toho nastavuje hodnotu čítače.

Ukázka a kód

S oběma komponentami si můžete pohrát zde:Demo:Plánování JavaScriptu s React Hooks

Veškerý zdrojový kód použitý v tomto článku je součástí DemoLab GitRepo. Prosím, neváhejte klonovat/forkovat/použít.

https://github.com/atapas/demolab/blob/master/code/src/demos/react/react-hook-js-schedule.js

Souhrnně

Abych to shrnula,

  • setInterval a setTimeout jsou metody dostupné v JavaScriptu pro plánování volání funkcí. Přečtěte si o tom více zde.
  • Je jich clearInterval a clearTimeout metody pro zrušení časovačů metod plánovače.
  • Tyto metody plánovače můžeme použít podobně jako jakékoli jiné funkce JavaScriptu v komponentě reakce.
  • Metody setInterval a setTimeout uzavírají. Při plánování tedy používá hodnotu stavové proměnné v době, kdy byla naplánována. Když se komponenta znovu vykreslí, vytvoří se nové uzavření, ale to nezmění hodnotu, která byla původně uzavřena. K nápravě této situace používáme useRef háček pro získání aktuální hodnoty stavové proměnné. Další informace o tomto řešení si můžete přečíst v tomto vydání GitHubu.

Doufám, že vám tento článek pomohl. Také by se vám mohlo líbit,

  • Pochopení uzavření JavaScriptu pomocí příkladu
  • Časová osa oznámení pomocí funkce React
  • Porozumění dynamickým importům, lenosti a napětí pomocí React Hooks
  • Dynamické přidání řádku tabulky pomocí React Hook
  • Být reaktivní – používání virtuálních DOM a rozdílů DOM
  • Průvodce krok za krokem:Smíchejte Redux s ReactJs

Můžete mi @me na Twitteru (@tapasadhikary) s komentáři, nebo je neváhejte sledovat.

Pokud vám to bylo užitečné, dejte like/sdílejte, aby se to dostalo i k ostatním. Klikněte prosím na Přihlásit se k odběru tlačítko v horní části stránky, abyste dostali e-mailové upozornění na mé nejnovější příspěvky.