Slot
Decomposition patterns (sprendžia kaip suskaldyti koda, kad nebūtų problemų). Padeda spręsti problemas tokias kaip god component - dideli komponentaim neaiškus kodas. Taip pat ir props drilling - kai komponentas perduoda per save per daug propsų. Taip pat ir global state folder.
Problema - labai dideli komponentai ir hook'ai, komponentas turi labai daug atsakomybės. Padeda spręsti su React child.
graph TD; ComponentA-->ComponentB; ComponentA-->ComponentC; ComponentA-->ComponentD; ComponentB-->ComponentE; ComponentD-->ComponentF; ComponentD-->ComponentG; ComponentD-->ComponentH; ComponentF-->ComponentI; ComponentF-->ComponentJ; ComponentF-->ComponentK;
ComponentD - pats daro kažka vieno ir deliguoja kažkai vaikams (t.y. perduoda vaikiniams komponentams).
Mes galime deliguoti renderiniti kažkokią dalį teviniams komponentui, ir gauti dali renderinimo per propsus.
Buvo:
graph TD; APP-->ComponentA; ComponentA-->ComponentB;
Tapo:
graph TD; APP-->ComponentA; APP-->ComponentB;
Tai yra SLOT esmė: komponentas A ir komponentas B nieko nežino vienas apie kitą.
Pavizdys
Situacija tokia: komponentai yra medyje vienas itarptas i kita ir t.t. Viskas pewrduodama propsais.
Table atsako ne vien uz table ir t.t. Turi savyje logikos.
<div className={styles.tableContainer) ref={tableContainerRef}> <table className={styles.table}> <thead> <tr> <th>Task</th> {getVisibleDays().map(day => { const isCurrentDay = new Date().getDate() === day && new Date().getMonth() === selectedMonth && new Date().getFullYear() === selectedYear; return ( <th key={day} ref={isCurrentDay? currentDayRef : null} className={isCurrentDay? styles.currentDay: undefined} > <div className={styles.dayHeader}> <span>{day}</span> <span className={styles.weekday}>{getWeekday (day)}</span> </div>
Sukursime kiekvienam dalykui komponentas ir perduodime per propsus. Pradedame tuo vaikinio mažiausio ir taip vis aukstyn.
Iškerpam btn
<div> <button className={styles.actionButton} onClick={(e) => handleUpdate Track (e, track)} title="Edit"> </button> <button className={${styles.actionButton} ${styles.deleteButton}`} onClick={(e) => handleDeleteTrack (e, track.id)} title="Delete" > </button> </div>
Paprastas komponentas:
import styles from "./tracks-actions.module.css"; export function TracksActions({}: { handleUpdateTrack: (e: React.MouseEvent, track: Track) => void; handleDeleteTrack: (e: React.MouseEvent, trackId: string) => void; }) { return ( <> <button className={styles.actionButton} onClick={(e) => handleUpdate Track (e, track)} title="Edit"> </button> <button className={${styles.actionButton} ${styles.deleteButton}`} onClick={(e) => handleDeleteTrack (e, track.id)} title="Delete" > </button> </> ) }
įdėsime jį į vidų kitam:
</div> <div className={styles.trackActions}> <TracksActions track={track} handleUpdateTrack={handleUpdateTrack} handleDeleteTrack={handleDeleteTrack} > </div> </div>
Analogiškai
actions,- perduomamas action renderinimas
export function TracksCell({ actions, getDayTracks, day, task, handleCellClick, }: { actions: JSX.Element; getDayTracks: (day: number, task: string) => Track []; day: number; task: string; handleCellClick: (day: number, task: string) => void; getDayTracks: (day: number, task: string) => Track[]; }){ return ( <td key={${day}-${task}`} className={styles.cell} onClick={() => handleCellClick (day, task)} > {(() => { const dayTracks = getDayTracks (day, task); if (dayTracks.length
Formuojam
<tbody> {getUniqueTasks().map((task) => ( <tr key={task}> <td>{task}</td> {getVisibleDays().map((day) => ( <TracksCell day={day} task={task} getDayTracks={getDayTracks} handleCellClick={handleCellClick} actions={ <TracksActions track={track} handleUpdateTrack={handleUpdateTrack} handleDelete Track={handleDeleteTrack} /> } </TracksCell> ))}
Parduodame per propsus jau surenderintus, bet nereikia jiems peruodti viau paramsus i tevini elementa.
T.y. SLOT'as
actions={ <TracksActions track={track} handleUpdateTrack={handleUpdateTrack} handleDelete Track={handleDeleteTrack} /> }
Dar vienas pavizdys:
import styles from "./tracks-table.module.css"; export function TracksTable({ tableContainerRef, days, children, }: { tableContainerRef: React. RefObject<HTMLDivElement>; days: React.ReactNode; children: React.ReactNode; }) { return ( <div className={styles.tableContainer) ref={tableContainerRef}> <table className={styles.table}> <thead> <tr> <th>Task</th> {days} <th>Total</th> </tr> </thead> <tbody>{children}</tbody> </table> </div> ); }
Tėvinis:
TracksTableparamsedaysgeneruojama jsx- kaip child props perduodmas kitas jsx
{getUniqueTasks().map((task)..
<TracksTable tableContainerRef={tableContainerRef} days={getVisibleDays().map((day) => ( <TracksDayHeadCell key={day} day={day} selectedMonth={selectedMonth} selectedYear={selectedYear} currentDayRef={currentDayRef} getWeekday={getWeekday} /> ))} > {getUniqueTasks().map((task) => ( <TracksTaskRow getTaskTotal={getTaskTotal} task={task} days={getVisibleDays().map((day) <TracksCell day={day} task={task} getDayTracks={getDayTracks} handleCellClick={handleCellClick}
Pliusai
- Gauname, kad komponentai vieni nuo kitų nepriklauso. Jeigu reikės dažnai keisti vieną komponentą, kitiems tai nebus aktualu.
- Kodas tampa žymiai lengviau perpanaidojamas
Props drillingnėra- DIP (Dependency Inversion Principle)
- lift state down, lift content up. Renderins rečiau.
- nusukuria gloabal state problemos
Minusai
- Blokuoja React.memo. Negalime naudoti, nes naudojant SLOT, kiekvienu renderinimu naujas komponentas
- Sunkokiai skaitomas kodas
- sunkiau suprasti visos programos veikimo logiką
Svarbu
- Neskaldyti perstipriai. Yra galimybė sukurti "neteikiančius naudos" komponentus, t.y. komponentas kuyris nieko nedaro