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:

  • TracksTable paramse days generuojama 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 drilling nė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