June 27, 2019
ReactEurope konference se opět konala v Paříži 23. a 24. května, leč letos jsem navštívil pouze dvou denní workshop, který ji předcházel. Vydal jsem se na něj již podruhé, po roce a znovu se vše odehrálo ve starém známém konferenčním centru Espace Charenton. Není to extra místo konání, ale francouzské občerstvení vše vynahradí. Croissantíčky s kávičkou a obložené bagety byly výborné.
Workshop vedl Greg Bergé, autor
Shipit,
SVGR nebo
SmoothUI a Oliver Tassiari, spoluzakladatel neméně známého
Material-UI.
Ačkoliv název akce nesl jméno React.js Workshop on React 17
, hlavním tématem
celého workshopu byly
Hooks,
které jsou součástí Reactu od února 2019, verze 16.8. Popravdě jsem za to byl i
rád, že se jedná o praktická támata, která je možné využít v praxi a na
produkci.
Úvodem jsme prolétli historii Reactu a základy. Jaká jsou jeho primitives, rozdíly mezi typy komponent, life cycle komponenty - fáze:
Také se zmínilo, že se již brzy můžeme těšit na Concurrent Mode umožňující schedulování renderování pro lepší performance nebo Suspense pro zjednodušení fetchovaní.
Dále se pokračovalo už jen s React Hooks. Jsou to funkce, které nám dovolují zacházet s lifecycle featurami uvnitř functional komponent. Hooky fungují pouze ve functional komponentách! Jsou základní tři useState, useEffect, useContext a pak několik dalších, pokročilých. Podrobněji o nich snad přístě.
Ale co bych zde rád více popsal je využití Render Props dohromady s React Hooks a navrhování Styled Components.
Tedy, jak bude vidět, Render Props ještě nejsou mrtvý! Pokud bych měl tento Hook, counter:
function useCounter() {
const [count, setCount] = useState(0)
useEffect(() => {
const interval = setInterval(() => setCount(count => count + 1), 1000)
return () => clearInterval(interval)
}, [])
return count
}
Použijeme hook useState()
pro nastavení lokálního statu a useEffect()
pro
spuštění hooku každou sekundu. Aplikujeme ho následovně v komponentě.
function Example() {
const count = useCounter()
return (
<div>
<OtherStuff />
<div>{count}</div>
</div>
)
}
Pak je zavolán setCount()
s každým tickem intevalu, je vygenerována nová
hodnota statu a Example
se přerendruje. Kromě něj se přerendruje i
OtherStuff
, který ale count
nepoužívá! Navíc, pokud by useCounter
vyhodilo
chybu, která komponenta bude ta s chybou? Example
! A proto budeme izolovat
logiku přes Render Props.
function Counter({ children }) {
const count = useCounter()
return children(count)
}
Children je obvykle node
element, ale zde má podobu funkce - Render Prop
!
function Example() {
return(
<div>
<OtherStuff />
<Counter>{(count) => <div>{count}</div>}</Couunter>
</div>
)
}
Co se tedy změnilo, Example
se nepřerenderuje a ani OtherStuff
. Counter
ale ano a pokaždé zavolá children funkci. Tedy nám Render Props dovolili pěkně
odizolovat renderování 🙂 A pokud bychom dále zabalili Counter
do
ErrorBoundaries
, efektivně odchytnou chybu.
Jednou z kapitol byl i pěkný příklad využití Styled Components, kdy se styly spojují s jednotlivým elementem za použitím ‘tagged template literals’. To odtraňuje mapování mezi komponentou a styly. Což znamená, že při definování stylů pak vytváříme normální React komponentu s připojenými styly. A hlavně pomáhají vyřešit následující scénář.
Máme základní požadavek pro vytvoření Card komponenty, která může vypadat následovně.
Což není žádný velký problém a naimplementovat ji třeba následovně.
const CardHeader = styled.div``
const CardBody = styled.div``
const Card = ({title, text}) => (
<div>
<CardHeader>{title}</CardHeader>
<CardBody>{text}</CardBody>
</div>
)
<Card title="Hello!" text="I am Card" />
Pak se ale na scéně objeví product owner s dalším požadavkem, že by chtěl odtranit titulek. Ok, přidáme podmínku k jeho vyrenderování.
const CardHeader = styled.div``
const CardBody = styled.div``
const Card = ({title, text}) => (
<div>
{title && <CardHeader>{title}</CardHeader>}
<CardBody>{text}</CardBody>
</div>
)
<Card text="I am Card" />
Potom se ale ozve UX designer, že by pozadí titulku mělo být zelené, což vypadá mnohem lépe. Jak je libo, i to můžeme udělat a přidáme novou props definující barvu pozadí.
const CardHeader = styled.div``
const CardBody = styled.div``
const Card = ({title, titleBackground, text}) => (
<div>
{title && (
<CardHeader style={{ backgroundColor: titleBackground}}>
{title}
</CardHeader>
)}
<CardBody>{text}</CardBody>
</div>
)
<Card title="Hello!" titleBackground="green" text="I am Card" />
Jen co změny doděláme, objeví se nový marketing manager s přáním, že by chtěl zobrazit malý ad banner namísto titulku. Mno, i to je možné a opět upravíme naší komponentu, aby se přizpůsobila i tomuto požadavku.
const CardHeader = styled.div``
const CardBody = styled.div``
const CardAd = styled.div``
const Card = ({title, titleBackground, ad, text}) => (
<div>
{add && <CardAd>{ad}</CardAd>}
{title && (
<CardHeader style={{ backgroundColor: titleBackground}}>
{title}
</CardHeader>
)}
<CardBody>{text}</CardBody>
</div>
)
<Card
titleBackground="green"
ad="👻 -50% on all articles, happy halloween!"
text="I am Card"
/>
Přidávání dalších a dalších požadavků už je ale neudržitelné. Jsou nekonečné.
Stačí málo a s využitím Styled Components
se komponenta může přizpůsobit mnoha
use casům.
export const Card = styled.div``
Card.Header = styled.div``
Card.Body = styled.div``
A vše by bylo mnohem mnohem jednodušší! 😌 Takto si můžeme nadefinovat pěkné API komponenty, a potom využít pouze potřebné části, případně komponentu doplnit o další elementy.
Jak by se vše přepsalo.
<Card>
<Card.Header>Hello!</Card.Header>
<Card.Body>I am a card</Card.Body>
</Card>
<Card>
<Card.Body>I am a card</Card.Body>
</Card>
<Card>
<Card.Header style={{ backgroundColor: 'green' }}>Hello</Card.Header>
<Card.Body>I am a Card</Card.Body>
</Card>
<Card>
<div
style={{
padding: 5,
backgroundColor: 'black',
color: 'white',
fontSize: 14,
}}
>
👻 -50% on all articles, happy halloween!
</div>
<Card.Body>I am a Card</Card.Body>
</Card>
Obecně se doporučuje začít co nejblíže k samotnému DOM nodu, nesnažit se vytvořit univerzální komponentu, ale složit ji z menších. Také by nemělo docházet k abstrakci příliš brzo, ale počkat na daná použití 😉
Na základě loňského absolvování celé konference a dalších recenzí od známých bych vyzdvihl workshop nad vlastní konferencí. React ekosystém se stabilizuje a za uplynulý rok se neobjevilo tolik novinek, a právě i proto se v letošním ročníku školení probíraly “pouze” Hooks.
Skvělá byla praktická doporučení, jak předejít různým problémům, se kterými se tvůrci Smooth UI a Material UI setkali behěm vývoje. Ať už šlo o využití referencí, či designování vlastního API komponenty.
Workshop bych doporučil a snad se na příštím ročníku budeme již zabývat Concurrent Mode nebo Suspense ✌️
Osobní blog zejména o Reactu a JavaScriptu. Sledujte mě na Twitteru