Komentáře k článku

React Hooks, které potřebujete znát

React s verzí 16.8 přináší zásadní novinku, a tou jsou Hooks, které mají přinést řešení pro hned 3 největší problémy, se kterými se v Reactu potýkáme. Implementace komponent pomocí tříd, sdílení logiky, nepraktický způsob práce s životním cyklem komponent. Představíme vám React Hooks a na konci ukážeme funkční příklad.

Zpět na článek

33 komentářů k článku React Hooks, které potřebujete znát:

  1. L.

    useState

    Já osobně však používám jeden useState, který nenese primitivní hodnotu, ale objekt,
    do kterého můžu vložit, co potřebuji.

    const [state, setState] = React.useState({ count: 0, … })

    Což je ovšem antipattern. Nutí v vás psát nastavování stylem:

    setState({...state, count: state.count + 1});
    

    To je jednak zbytečně dlouhé, jednak ošklivé a hlavně to vede k chybám. Když statement viz výše provedete třeba v průběhu zpracování eventu 2x, tak se pak hrozně divíte, proč se čítač nezvýšil o 2 ale jen o 1, vždyť jste to přece spustili 2x… Podobně si můžete přepsat zpět změny v některých proměnných.

    POKUD už byste chtěli mít víc proměnných v jednom objektu, které se mění (občas) zvlášť, tak na to je useReducer(). Ale jinak je mnohem lepší a čistší použít hezky pro každou nezávislou proměnnou její vlastní useState().

    1. L.

      Re: useState
      Tak pardon, ještě upřesnění. Dohledal jsem, že i když o to React dokumentace nezmiňuje, i do set funkce useState hooku je možno dát funkci. Tedy pokud byste psal:

      setState((s) => ({...s, count: state.s + 1}));
      

      Tak by vícenásobné použití fungovalo OK. Nicméně stále je to další past, kód je komplikovanější a IMO je to zbytečné míchání dohromady věcí, které spolu nesouvisí.

      1. Pavel KřížAutor příspěvku

        Re: useState
        Dobrý den. Je to jak sám píšete a jak píšu i já v odstavci o useState, kde právě předání funkce popisuji. Upřednostňuji používání useState tímto způsob, jelikož to je při práci se stavem přímo patrné. Když budu mít místo volání setState(…) někde v kódu setCount(…), tak na první pohled netuším, že tím nastavuji stav, protože to může být funkce, která dělá něco úplně jiného. Je to, hádám, otázka preferencí. Oba přístupy jsou možné a mají své opodstatnění.

        1. L.

          Re: useState
          Tak pokud se vám může stát, že setCount() nenastavuje count, ale dělá něco úplně jiného, tak stejně se může stát, že setState() nenastavuje stav ale dělá něco úplně jiného, ne? To není ani tak otázka preferencí jako spíš kultury kódu.

          1. Pavel KřížAutor příspěvku

            Re: useState
            setState je obecně známý název funkce pro nastavení lokálního stavu, která je známá už od class komponent, takže každému její název evokuje, co dělá, ale setCount může být nějaký callback, který jsem například dostal v props a nemusí s lokálním stavem komponenty souviset.

  2. Peter

    Naco hooks, iba dalsia komplikacia
    Skratka hooky su nieco co nepotrebujete, lebo lepsie to ide bez nich pomocou class komponent :)

    1. Pavel KřížAutor příspěvku

      Re: Naco hooks, iba dalsia komplikacia
      Takto můžete říct, že nepotřebujete ani React, protože si vystačíte s HTML a vanilla JavaScriptem.
      Jak popisuje článek, hooks řeší hned 3 problémy class komponent.

      • Sdílení logiky
      • Zbavíme se tříd (a řešení kolem this)
      • Praktické life cycle hooks

      Sdílení kódu mezi class komponentami pomocí HoC/Render Props je oproti hooks prostě pain, který vede k wrapper hell. Komponenty jsou navíc díky hooks menší.

      Nic Vám nebrání stále používat class komponenty. Hooks nepřináší žádné breaking changes. Nicméně směr Reactu je jasný. Je možné (zde pouze můj názor), že jednou budou class komponenty prohlášeny za obsolete.

      Pro inspiraci doporučuji například tento záznam z React Conf.

      1. Peter

        Re: Naco hooks, iba dalsia komplikacia

        Nicméně směr Reactu je jasný.

        Ano, smer Reaktu je jasny ako smer kazdej technologie ktoru ovladne peklo globalnych funkcii so side efektami. :)

        Myslite ze OOP vzniklo preto aby sa pokazila krasa proceduralneho programovania, globalnych premennych a globalnych funkcii? :)

        1. Pavel KřížAutor příspěvku

          Re: Naco hooks, iba dalsia komplikacia
          V JS máme moduly, do kterých hooks (stejně jako jiné funkce/třídy/cokoliv) můžete organizovat a zároveň vás hooks rozhodně nenutí používat jakékoliv globální proměnné, pokud to tak nevyžaduje use case. Tedy žádné globální funkce měnící globální proměnné nevznikají, ale pokud potřebujete například manipulovat s document.title (jako já v příkladu), děláte to v hooku úplně stejně, jako by se to udělalo v class komponentě.

          Btw OOP je celé o side efektech, nemyslíte?

          Když budu chtít sdílet logiku mezi class komponentami, mohu použít například HoC, což bude znamenat vytvoření class komponenty, která danou logiku ponese a bude ji poskytovat komponentám, které wrappuje. Pokud budu chtít to samé řešit přes hooks, tak budu muset vytvořit custom hooks, což je funkce, která si uvnitř bude řešit vše, co class komponenta, pouze je kratší, čitelnější a zbavím se wrapper hell.

          Můžete prosím uvést příklad, na kterém bude zjevný benefit class komponent oproti hooks?

          1. Peter

            Re: Naco hooks, iba dalsia komplikacia

            Btw OOP je celé o side efektech, nemyslíte?

            Ano, samozrejme a OOP je o manazovani a enakpsulacii tych side efektov, preto tie classes.
            To co robite vy a hooks je ak to nechapete iba ze ste nahradili class funkciou ktora uklada svoj stav na globalnej urovni v module. Chapete co tie hooky robia a preco je to svinstvo? Vy nadavate na class ale iba ste ho nahradili modulom? Chapete vy vobec co robite?

            1. Pavel KřížAutor příspěvku

              Re: Naco hooks, iba dalsia komplikacia
              Jiný komentující Vám sem vkládal ukázku, která jasně předvádí použití hooks vs. class komponenty. Znovu Vás žádám, ukažte vlastní příklad, který předvede, že hooks nutí psát globální proměnné, když do nich přepíšete ekvivalentní funkcionalitu z class komponenty.

              Představa, že potřebujete s hooks používat globální proměnné, je naprosto lichá.
              Doporučuji nejprve projít dokumentaci a zjistit, co hooks vlastně jsou, než budete pokračovat v diskuzi.

              Ukažte příklad, kdy budete demonstrovat, co tvrdíte, jinak se nepohneme z místa.

              1. Peter

                Re: Naco hooks, iba dalsia komplikacia
                Uvedomujete si ze vase globalne premenne su moduly?
                Takyto styl kodenia mozete robit iba pereto ze bezite v jedno vlakne.
                Z hladiska OOP su vase moduly singletony a hoogks ich staticke metody.
                Znovu sa pytam, chapete co robite?

                1. Lee

                  Re: Naco hooks, iba dalsia komplikacia
                  Ano, JS běží v jednom vlákně. K čemu přesně je mi dobré, v kontextu Reactu, psát komponenty jako třídy?

                  Ten příklad prosím.

                2. Pavel KřížAutor příspěvku

                  Re: Naco hooks, iba dalsia komplikacia
                  Bavíme se ještě o Reactu? Ten příklad prosím. Na něm nejlépe ukážete, v čem v jednovláknovém JS bude dobré psát komponenty jako třídy, a také jak řešíte například sdílení logiky mezi class komponentami. Děkuji.

                  1. Vítek Heřman

                    Re: Naco hooks, iba dalsia komplikacia
                    Ahoj Pavle,

                    přestože se z toho kolega snaží asi dělat atomovou válku, tak mám pocit, že ve své podstatě naráží na konstrukci:

                    import React from 'react'
                    
                    const [count, setCount] = React.useState(0)
                    

                    count a setCount jsou zde proměnné modulu. Hned v úvodní dokumentaci v Reactu příklad vypadá trochu jinak:

                    import React from 'react'
                    
                    function Component() {
                      const [count, setCount] = React.useState(0);
                    
                      return ...;
                    }
                    

                    V druhém případě jsou count a setCount v uzávěru funkce Component, nejsou tedy globální v modulu, ale lokální v komponentě (resp. uzávěru funkce)

                    Možná se mýlím, to jen takový rychlý postřeh :-)

                    1. Pavel KřížAutor příspěvku

                      Re: Naco hooks, iba dalsia komplikacia
                      Ahoj Vítku :-). Máš pravdu, tohle je chyba. Chtěl jsem napsat pouze ten hook, bez balastu kolem, ale pak jsem si řekl, že tam radši dám i ten import, ale už jsem zapomněl hook obalit funkcí. Pokud je toto skutečně důvodem celé této výměny názorů, tak se omluvím a chybu samozřejmě opravím, ale z celé diskuze mi vůbec nevyplynulo, že by mohlo jít o zapomenutý kus kódu (i když mám pocit, že to nebude tak jednoduché). Díky moc za upozornění.

                      1. Vítek Heřman

                        Re: Naco hooks, iba dalsia komplikacia
                        Není zač :-)

                        Trollům doporučuju se neomlouvat, nic jim nevysvětlovat, ani na ně nijak nereagovat. Jinak následuje akorát ještě blbější pocit. V článku chyba není, přišlo mi celkem zřejmé, že šlo o stručný ilustrační snippet. Jen jsem chtěl upozornit na absurditu toho, jaké záminky trollové používají pro své útoky a že za tím opravdu nějaké rozumné argumenty nebývají. Pokud je argument rozumný, lze ho obvykle i dobře zformulovat.

            2. Lee

              Re: Naco hooks, iba dalsia komplikacia
              U nás s kolegy píšeme hooky od vydání Reactu 16.8. a žádné globální proměnné nepoužíváme. Očividně vůbec nevíte, o čem mluvíte. Nastudujte si téma. Taky by bylo pěkné, podložit co říkáte příkladem class components proti functional components s hooky, kde nám předvedete, o čem to celou dobu mluvíte. Když si ten článek (nebo třeba dokumentaci Reactu) přečtete, tak uvidíte, že stav (stav komponenty), případně jen lokální proměnnou, která si bude něco pamatovat, můžete řešit pomocí hooků useState/useReducer a useRef, kteté máte ve scope dané komponenty/custome hooku, takže žádné globální proměnné.

              Ukažte příklad, kde prokážete, co tvrdíte.

    2. L.

      Re: Naco hooks, iba dalsia komplikacia
      Doporučuji si přečíst článek. Tam máte jasně napsáno, v čem jsou výhody hooků. Jakmile byly ve stable, ihned jsme na ně přešli a nemůžeme si je vynachválit, jak nám kód zjednodušují a zpřehledňují.

      Dám příklad: Řekněme, že mám v projektu několik komponent u kterých chci, aby mi po nějaké době od zobrazení vyhodili alert. Řešení s class komponentou (a service).

      Service:

      const TimeAlertSevice = {
        installAlert: (nazev) => window.setTimeout(
          () => alert(`Komponenta ${nazev] je zobrazena příliš dlouho`),
        5000);
      
        removeAlert: (handle) => window.clearTimeout(handle);
      }
      

      Vlastní třída:

       class MojeKomponenta extends React.Component {
         componentDidMount() {
           this.timeoutHandle = TimeAlertSevice .installAlert('MojeKomponenta ');
         }
      
         componentWillUnmount() {
           TimeAlertSevice.removeAlert(this.timeoutHandle);
         }
       }
      

      Takovéhle použití sdílené funkcionality je možné, ale do používající komponenty se motá implementační logika – komponenta musí „vědět“, že musí zavolat jednu funkci při mount, schovat si číslo a s tím zavolat druhou funkci při unmount.

      Je možné to napsat jako HOC, čímž se použití smrskne na aplikaci HOC a logika se tak nemotá do používajících komponent (a není vlastně třeba service), nicméně to zas vede k wrapper hell.

      Za použití hooků je všechno velmi elegantní. Knihovní funkce:

        const useTimeAlert = (nazev) => useEffect(() => {
          const handle = window.setTimeout(
            () => alert(`Komponenta ${nazev] je zobrazena příliš dlouho`),
            5000
          );
          return () => window.clearTimeout(handle);
        }, []);
      

      A použití:

        const MojeKomponenta = ({...props...}) => {
          useTimeAlert('MojeKomponenta');
          ... render
        }
      

      Použití na jeden řádek, žádná implementační logika „neprosakuje“ ven, žádný wrapper hell, prostě jen čistý a čitelný kód :-)

      1. Peter

        Re: Naco hooks, iba dalsia komplikacia

        Zbavíme se tříd (a řešení kolem this)

        Nenechajte obmedzovat, navrhujem vam zajst s tou optimalizaciou a riesenim problemov este dalej: Zbavte sa aj funkcii. :)

      2. Marfusios

        Re: Naco hooks, iba dalsia komplikacia
        No nevim, pro me osobne ukazka s tridou je krasne cista a citelna. Je proste videt exekucni flow a je mozne si na prvni dobrou domyslet kdy se ktera metoda zavola.

        V druhem pripade bych byl bez dokumentace ztraceny.
        Strasne moc nepochopitelnych return typu.
        Nejake parametry vycucane z prstu ala [].
        Ta zivotnost te useTimeAlert… bez dokumentace nejde odhadnout.

        1. Zbyšek Lipka

          Re: Naco hooks, iba dalsia komplikacia
          muzu vedet co je to zde za syndrom ala Blesk?
          ze po precteni nadpisu clanku znam obsah a podle toho se vyjadruji v diskuzi:
          aneb – pokud byste si dal tu praci a claenk precetl tak rozhodne neni strasne moc nepochopitenych return typu ani parametru vycucanych z prstu :)

      1. Peter

        Re:
        Pozrite si prosim tie linky co som poslal, maju tam odvolavky. A samozrejme google. :)
        Napriklad ze hooks su preto aby sa odstranili classes… blbost, to autor nieco nepochopil (okrem ineho).
        Tento clanok a autor potvrdzuje to stare porekladlo ze ten kto to nevie to uci. :)

        1. Martin Hassman

          Re:

          Já stále čekám, až napíšete, s čím konkrétně máte problém. Stačí citovat konkrétní věty z článku a napsat co je na nich špatně, jak by měly znít lépe. Rád se na to pak podívám. Zatím to jsou jen takové dojmy a pocity. S tím se nic nenadělá. Autor zatím (i zde v diskusi) odvádí dobrou práci.

    1. Pavel KřížAutor příspěvku

      Re:
      Obecně k věc:.
      můj článek popisuje novou featuru hooks a základní použití třech z nich s tím, že vycházím z dokumentace, přednášek (nejen) členů React core týmu a vlastních zkušeností. Opakovaně Vás žádám o ukázku kódu, kde mi předvede, jak hooks a functional componenty škodí.

      Teď k článkům, které jste sem vložil:
      četl jste ty články? Nebo jen jejich nadpisy?

      1. článek
        • hezký článek, souhlasím s ním (kdyby jste si ho přečetl, tak ho sem vkládat nejspíš nebudete)
        • souhlasím, že class komponent se jen tak obsolete nestanou, jelikož je spousta projektů je na nich postavená, to je fakt
        • pattern HoC pro sdílení logiky má řadu problémů, jak ukazuje Michael Jackson (tvůrce známé knihovny React Router) ve své skvělé přednášce
          a doporučuje přejít na pattern Render Prop (AKA Function as Child), který některé z problémů řeší
          (konflikty názvů injektovaných props, nejednoznačnost zdroje injektování…), ale wrapper hell zůstává. V době přednášky, ještě hooks, které tyto problémy řeší, neexistovaly
        • hooks skutečně (zatím) neposkytují řešení pro life cycle metody componentDidCatch a getSnapshotBeforeUpdate. Obě tyto metody, ale běžně použijete velmi zřídka, protože
          error boundaries stačí použít v podstatě na jednom místě v projektu a getSnapshotBeforeUpdate je pro specifické případy
          (od vydání jsem getSnapshotBeforeUpdate, což je asi víc než 1,5 roku, použil snad jednou).
        • co se týče testování komponent, jak článek zmiňuje, záleží, jaký způsob testování a tooling používáte.
          Pokud testy neřeší interní implementaci komponent, ale její veřejné API, jak by správně mělo být, tak není problém.
          Některé testováci tooly, jako Enzyme, ještě pracují na ladění podpory například pro shallow rendering, což je skutečně dobré zmínit
        • Obecně je obsah článku pěkný a v podstatě jen upozorňuje na některé věci, na které je dobrý si dát pozor a hooks několikrát chválí. Jeho titulek považuji částečně za clickbait, protože (stejně jako asi Vy) jsem dle něho čekal hate, který se nedostavil
      2. článek
        • popisuje probém s polem závislostí u useEffect, kde se autor chytil do pasti s mělkým porovnáním, což je ale obecné a popsané chování, které platí třeba i pro bázovou třídu PureComponent a její implementaci shouldComponentUpdate.
        • dále se věnuje problému s custom hookem, který očividně nepoužívá korekteně, což mu i naznačují vývojáři v komentářích
        • tento článek beru spíše jako nepochopení technologie a popisu frustrace, která plyne ze špatného použití

      Jiný komentující však upozornil, že dost možná toto celé odstartovala má chyba v kódu:

      import React from 'react'
      
      const [count, setCount] = React.useState(0)
      

      Ten hook skutečně nemá být na úrovni modulu, ale zapouzdřený do funkce. Chtěl jsem pouze naznačit použití hooku samotného, ale pak jsem si říkal, že tam radši ještě dopíšu i ten import, a už jsem zapomněl dopsat i funkci kolem něj. Je to chyba z nepozornosti, kterou opravím, ale pokud to byl skutečně zdroj tohoto celého, mohl jste mě na to upozornit rovnou.

      1. Peter

        Re:

        Opakovaně Vás žádám o ukázku kódu, kde mi předvede, jak hooks a
        functional componenty škodí.

        Citali ste moje komentare? ;)

  3. Peter

    Mimochodom tento clanok je na urovni hello world a vzhladom na profil autora ho mozno povazovat iba za PR clanok. Clanok je de facto osobna inzercia a promo autora.
    Nic nove clanok neprinasa okrem tej averzie a fobie voci triedam a slovicku this.

    1. Pavel KřížAutor příspěvku

      Re:
      Článek byl myšlen jako lehký úvod do problematiky s tím, že jsem uvažoval o pokračování a předvedení pokročilých konstrukcí. Článek má totiž omezený rozsah a rozebrat všechno naráz prostě nejde.

      To s těmi třídami a „this“ (v kontextu JavaScriptu!) bych se Vám pokusil vysvětlit, ale cokoliv co napíšu, tak ignorujete a vezmete si z toho první odstavec, takže to vynechám.

      Ukázku kódu tady asi neuvidíme, protože z Vašich komentářů mi je jasné, že Vám nedostatečné znalosti Reactu nedovolují ho vytvořit.

      Děkuji Vám za vytvoření naprosto zbytečně toxické atmosféry a cíleného dehonestování mé osoby místo toho, abychom vedli konstruktivní debatu. Dál už na Vás nebudu reagovat, protože to nemá smysl.

      1. Zbyšek Lipka

        Re: obdiv
        Dobry den,
        bezne tady do diskuzi neprispivam, ale po precteni reakci diskutujiciho Peter jsem proste musel vyjadrit obdiv k vasi trpelivosti s lidmi postradajicimi zakladni programatorske kvality jako je treba logika ci vecna diskuze :)
        p.s. a diky za clanek, zvladam bezne anglictinu, ale potesi si obcas precist neco o Reactu v materstine a taky je dobry vedet, ze v nasich lukach a hajich se nespi :)

        1. Pavel KřížAutor příspěvku

          Re: obdiv
          Dobrý den,
          já jsem v první řadě pořád doufal, že to celé povede k porozumění obou stran, ale bohužel se tak nestalo. Když došly argumenty, začalo se útočit na osobní úrovni, čehož už jsem se nechtěl účastnit. Škoda.

          Každopádně článek je pouze úvodem. Celá problematika kolem hooků je rozsáhlá a obnáší hlavně změnu mindsetu. Hodlám časem napsat pokračování, které se zaměří na konkrétní případy užití, které jsou pokročilejší.

          Každopádně moc děkuji za vlídné slovo, které v této diskuzi těžko pohledat. :-)

Napsat komentář

Tato diskuse je již příliš stará, pravděpodobně již vám nikdo neodpoví. Pokud se chcete na něco zeptat, použijte diskusní server Devel.cz

Zdroj: https://www.zdrojak.cz/?p=23413