State kezelés Next.js-el II.
Mi is a prop drilling, ismerjük az ellenséget, hogy küzdhessünk ellene
A prop drilling arra a gyakorlatra utal, hogy egy mélyen beágyazott komponenshez adatokat továbbítanak szülő/gyerek - szülő/gyerek komponenseken keresztül.
Ennek a módszernek megvan az a hátránya, hogy a komponensek, amelyen keresztül az adatok kézbesítése kerülnek, csupán csatornaként szolgálnak, hogy az információ eljusson a végső rendeltetési helyére.
A "prop drilling" kifejezés arra a folyamatra utal, amikor arra kényszerítjük ezeket az komponenseket, hogy vegyenek át olyan adatokat amelyek nem szorosan hozzájuk tartoznak, és adják tovább azokat a következő komponensnek, amely továbbküldi a következő komponensnek, és így tovább, amíg el nem éri a célt. Ez a komponens újrafelhasználhatóságát ez súlyosan befolyásolhatja, valamint amennyiben változik ez az adat, így a közvetítő komponensek felesleges rerenderelődésével jár.
Lehetséges megoldások
Most, hogy világossá vált, hogy mit akarunk elérni, milyen problémával szembesülünk, meg kell vizsgálnunk a lehetséges megoldásokat. Az alábbiakban a prop drilling technika alternatíváinak hiányos listája található.
- React Context API, useState, useReducer (beépített megoldás)
- Redux
- React Query
- Zustand
- Jotai
- Mobx
Annak ellenére, hogy nagy rajongói vagyunk a Reduxnak, ha appunk nem túl komplex, javasoljuk a beépített megoldások használatát az állapotkezeléshez.
Amennyiben azonban az app igényel komplexebb state kezelési megoldásokat, akkor mi a külső megoldásokból a Redux segítségét vesszük igénybe.
Cikkünk nem hivatott a Redux részletes bemutatására, ám ismertetjük a Next.js-el való integrálásának lehetőségét.
React Context API vs Redux
- Context API
- Beépített eszköz, amelyet a React magában foglal (csomag méretet nem növel)
- Minimális beállítást igényel
- Kifejezetten statikus adatokhoz tervezték, amelyeket nem gyakran frissítenek vagy frissítenek
- Új kontextusok hozzáadásához a semmiből kell létrehozni minden alkalommal a provider-t
- A felhasználói felület logika és az state-kezelési logika ugyanabban az összetevőben találhatók
- A hibakeresés nehéz lehet erősen beágyazott komponens struktúra esetén még a Dev Tool használatával is
- Redux
- További csomag telepítése szükséges, ami növeli a végső csomag méretét
- A React alkalmazással való integrálása extra beállítást igényel
- Statikus és dinamikus adatokkal is remekül működik
- Könnyen bővíthető az új adatok/műveletek könnyű hozzáadásának köszönhetően a kezdeti beállítás után
- Jobb kódszervezés külön felhasználói felület logikával és állapotkezelési logikával
- Hihetetlenül erős Redux Dev Tools a hibakeresés megkönnyítésére
A beépített megoldások: React Context API, useState, useReducer
Fontos megjegyezni, hogy a szolgáltatók (provider-ek) használata kifejezett figyelmet igényel, a kompozícióra mindig legyünk kiemelt tekintettel.
-
Létrehozhatják az úgynevezett "szolgáltatói poklot" (provider hell), amely feltűnő hasonlóságot mutat a "visszahívási pokol"-hoz (callback).
// ... imports const App = () => { // ... some code return ( <> <ReduxProvider value={store}> <ThemeProvider value={theme}> <OtherProvider value={otherValue}> <OtherOtherProvider value={otherOtherValue}> {/** ... other providers*/} <HellProvider value={hell}> <HelloWorld /> </HellProvider> {/** ... other providers*/} </OtherOtherProvider> </OtherProvider> </ThemeProvider> </ReduxProvider> </> ) }
Ebben a cikkben arról olvashatunk, hogyan lehet elkerülni a szolgáltató poklot.
-
Sok fejlesztő össze van zavarodva a Context és a Redux kapcsán, a Context nem helyettesíti a Reduxot, csak egy könnyű súlyú helyettesítője. Van néhány hasonlóság és átfedés, de jelentős különbségek vannak a képességeikben. Különféle eszközökről van szó, különböző dolgokra és célokra használjuk őket. A Context csupán egy eszköz, nem kezel semmit, azt a fejlesztő teszi a useState/useReducer használatával.
-
Példa egy provider-re - Bár a példában nem használjuk a useReducer-t, ez bonyolultabb statek esetén használatos.
import {createContext, ReactNode, useContext, useState,} from "react" type ThemeProviderProps = { children: ReactNode } type ThemeContext = { isPrimary: boolean } type ThemeDispatchContext = { changeTheme: () => void } const ThemeContext = createContext({} as ThemeContext) const ThemeDispatchContext = createContext({} as ThemeDispatchContext) export function useTheme() { return useContext(ThemeContext) } export function useDispatchTheme() { return useContext(ThemeDispatchContext) } const ThemeProvider = ({children}: ThemeProviderProps) => { const [isPrimary, setIsPrimary] = useState<boolean>(true) const changeTheme = () => { setIsPrimary(prevState => !prevState) } return ( <ThemeDispatchContext.Provider value={{changeTheme}}> <ThemeContext.Provider value={{isPrimary}}> <div className={ isPrimary ? "themeable-primary-theme" : "themeable-secondary-theme" } > {children} </div> </ThemeContext.Provider> </ThemeDispatchContext.Provider> ) } export {ThemeProvider}
A cikk itt folytatódik.