Vas tancar el Mòdul 1 sabent com React converteix les teves funcions en pantalla: JSX es transforma en objectes, aquests objectes formen un arbre i la reconciliació decideix què s'ha de tocar del DOM real. Ara toca pujar un nivell i mirar el problema des del disseny, no des del motor. Un component no és només «una funció que retorna JSX»: és la unitat de disseny de la teva aplicació, la caixa en què decideixes quin marcatge, quina lògica i quin estil viuen junts. Aquesta lliçó tracta de la decisió més freqüent i més determinant que prendràs a React: on posar les línies divisòries. Partirem de l'esbós real de la pantalla de catàleg de CicloUrbano, la trossejarem en components amb criteri, dibuixarem la seva jerarquia i organitzarem els fitxers perquè dins de vint components continuïs trobant el que busques.
Contingut
- Què encapsula realment un component
- De l'esbós als components: la pantalla de catàleg de CicloUrbano
- Tres criteris per decidir els límits d'un component
- L'arbre de components: relació pare i fill
- Components de presentació i components contenidors
- Organització de fitxers i convencions de noms
- Exportació per defecte enfront de l'exportació amb nom
- Compondre: muntar la pantalla completa
- El límit que arrosseguem: les dades continuen fixes
- Què encapsula realment un component
Al Mòdul 1 vas escriure Benvinguda i TargetaBicicleta com a funcions que retornen JSX. Aquesta és la mecànica. La idea de fons és una altra: un component agrupa en un sol lloc les tres coses que defineixen un tros d'interfície.
| Què encapsula | A CicloUrbano, dins de TargetaBicicleta |
|---|---|
| Marcatge | L'<article>, l'<h3> amb el model, els <p> amb tipus, estat i preu |
| Lògica | Com es formata el preu, quin text correspon a cada estat, si el botó de reservar es mostra o no |
| Estil | La classe targeta-bicicleta i les variants que depenen del tipus de bicicleta |
Durant anys la bona pràctica en desenvolupament web va ser justament la contrària: HTML en un fitxer, CSS en un altre, JavaScript en un tercer. React proposa separar per preocupació funcional en lloc de per tecnologia. L'argument és senzill: quan et demanen «canvia com es veu una bicicleta al catàleg», no toques «el CSS» ni «el JavaScript», toques la targeta de bicicleta. Que tot el que defineix la targeta estigui a la vista en un mateix fitxer és el que fa que el canvi sigui ràpid i segur.
Això té tres conseqüències pràctiques que convé interioritzar des d'ara:
- Un component és reemplaçable. Si
TargetaBicicletacompleix el seu contracte, pots reescriure-la sencera sense que res de la resta de l'aplicació se n'assabenti. - Un component és reutilitzable. El mateix component serveix al catàleg, al detall d'una estació i a la pantalla de reserves.
- Un component és raonable en aïllament. Pots entendre què fa
TargetaBicicletasense llegirApp.jsx. Quan això deixa de ser cert, gairebé sempre és perquè el component fa massa coses.
- De l'esbós als components: la pantalla de catàleg de CicloUrbano
Aquest és l'esbós de la pantalla que construirem durant els pròxims mòduls: el catàleg de bicicletes de CicloUrbano.
┌──────────────────────────────────────────────────────────┐ │ CicloUrbano │ │ Lloga una bicicleta urbana al teu barri… │ │ Catàleg · Estacions · Les meves reserves │ ├──────────────────────────────────────────────────────────┤ │ Bicicletes disponibles │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Urbana Clàssica [ disponible ] │ │ │ │ urbana · Plaça Major · 2,50 € / hora │ │ │ └────────────────────────────────────────────────────┘ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Elèctrica Pro [ llogada ] │ │ │ │ electrica · Plaça Major · 4,00 € / hora │ │ │ └────────────────────────────────────────────────────┘ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Càrrega Max [ manteniment ] │ │ │ │ carga · Parc Nord · 5,50 € / hora │ │ │ └────────────────────────────────────────────────────┘ │ ├──────────────────────────────────────────────────────────┤ │ CicloUrbano — Servei de lloguer de bicicletes │ │ Estacions: Plaça Major · Parc Nord · Est. Central │ └──────────────────────────────────────────────────────────┘
El mètode per trossejar-lo és sempre el mateix: envolta amb un rectangle cada zona que tingui un nom propi i comprova si aquest nom descriu una responsabilitat. Aplicant-lo en surten cinc components:
| Component | Zona de l'esbós | Responsabilitat |
|---|---|---|
Capcalera |
Franja superior | Identitat del lloc i navegació principal |
LlistaBicicletes |
Secció central | Presentar el conjunt de bicicletes amb el seu títol |
TargetaBicicleta |
Cada requadre | Mostrar una bicicleta |
EtiquetaEstat |
El distintiu [ disponible ] |
Traduir un estat a un distintiu visual |
PeuDePagina |
Franja inferior | Informació legal i de contacte |
Fixa't en dues decisions que no són òbvies:
LlistaBicicletesexisteix encara que de moment sembli un simple contenidor. Li donem entitat pròpia perquè més endavant acollirà els filtres per tipus i estat i el missatge de «no hi ha resultats». És la zona que creixerà, i tenir ja la seva caixa evita que aquest creixement es vessi sobreApp.EtiquetaEstatexisteix encara que només sigui un<span>. El distintiu apareixerà també al detall de l'estació i al llistat de reserves, i sempre amb les mateixes regles de color. Un component de dues línies que es fa servir en tres llocs està més que justificat.
- Tres criteris per decidir els límits d'un component
No hi ha una regla mecànica, però sí tres criteris que, aplicats en aquest ordre, resolen gairebé tots els casos.
Criteri 1: responsabilitat única
Un component hauria de poder-se descriure en una frase sense la paraula «i».
- ✅ «
TargetaBicicletamostra les dades d'una bicicleta.» - ❌ «
Catalegmostra la capçalera i filtra les bicicletes i pinta les targetes i gestiona el peu.»
Quan la descripció necessita conjuncions, tens un candidat a divisió. Compte amb el fals positiu contrari: dividir tant que cada component sigui una etiqueta HTML disfressada. Un <TitolSeccio> que només retorna <h2> no afegeix res.
Criteri 2: reutilització
Si un fragment apareix —o apareixerà— en més d'un lloc amb el mateix aspecte i les mateixes regles, és un component. Aquest criteri és el que justifica EtiquetaEstat: el mapatge de disponible a verd i de mantenimiento a vermell és una decisió que volem escrita una sola vegada. Si estigués copiada en tres pantalles, el dia que canviï la paleta caldrà recordar-se dels tres llocs.
Compte amb el revers: no creïs un component reutilitzable abans de tenir el segon ús. Dissenyar per a una reutilització imaginària produeix components amb contractes retorçats que al final no encaixen en el segon cas real.
Criteri 3: mida manejable
No hi ha un número màgic de línies, però sí senyals fiables que un component s'ha passat de mida:
| Senyal d'alarma | Què sol indicar |
|---|---|
| No cap en una pantalla de l'editor | Fa més d'una cosa |
| El JSX s'imbrica més de quatre o cinc nivells | Hi ha una secció interior que mereix el seu propi component |
| Costa posar-li nom | Els límits estan mal traçats |
| En canviar alguna cosa toques parts que no tenien relació | Responsabilitats barrejades |
I un senyal que has dividit massa: per entendre una pantalla senzilla has d'obrir set fitxers i saltar entre ells. La fragmentació excessiva també és deute tècnic.
Un quart criteri que arribarà més endavant
Quan estudiïs l'estat (lliçó State) apareixerà un criteri addicional molt potent: el que canvia junt, viu junt. Les parts de la interfície que s'actualitzen alhora solen pertànyer al mateix component. De moment queda't amb els tres primers.
- L'arbre de components: relació pare i fill
Quan un component fa servir un altre dins del seu JSX, s'estableix una relació pare → fill. El conjunt de totes aquestes relacions forma l'arbre de components, que és el mapa mental de la teva aplicació.
flowchart TD
APP[App] --> CAB[Capcalera]
APP --> LIS[LlistaBicicletes]
APP --> PIE[PeuDePagina]
CAB --> BIE[Benvinguda]
LIS --> T1[TargetaBicicleta]
LIS --> T2[TargetaBicicleta]
LIS --> T3[TargetaBicicleta]
T1 --> E1[EtiquetaEstat]
T2 --> E2[EtiquetaEstat]
T3 --> E3[EtiquetaEstat]
Tres precisions importants sobre aquest diagrama:
- Pare i fill no és herència.
TargetaBicicletano hereta res deLlistaBicicletes; simplement apareix dins del seu JSX. React no fa servir herència entre components, fa servir composició, i aquest contrast s'estudia a fons a Composició vs Herència. - Un mateix component apareix tantes vegades com es faci servir. A l'arbre hi ha tres nodes
TargetaBicicletaperquè hi ha tres bicicletes en pantalla. Cadascun és una instància independent: comparteixen el codi, no les dades ni l'estat. - La informació baixa per l'arbre. El flux de dades a React és unidireccional: de pare a fill. És exactament el camí que recorreran les props a la lliçó Props.
Aquest arbre és també el que veuràs a la pestanya Components de React DevTools, l'extensió que vas instal·lar a la lliçó 01-02. Obre-la mentre construeixes: comparar l'arbre que has dibuixat amb el que mostra React és la manera més ràpida de detectar que la teva estructura mental i el teu codi s'han separat.
- Components de presentació i components contenidors
Amb el temps notaràs que els teus components cauen de manera natural en dues famílies.
| Components de presentació | Components contenidors | |
|---|---|---|
| Per a què serveixen | Pintar alguna cosa | Decidir què es pinta |
| D'on treuen les dades | Els les donen des de fora | Les obtenen, filtren o ordenen |
| Tenen estat | Normalment no | Sovint sí |
| Reutilització | Alta: serveixen en qualsevol pantalla | Baixa: són específics d'un cas |
| Facilitat de prova | Molt alta: entrada → sortida | Menor: cal simular dades i lògica |
| A CicloUrbano | TargetaBicicleta, EtiquetaEstat, PeuDePagina |
LlistaBicicletes, App |
La utilitat de la distinció és pràctica, no dogmàtica: empeny la lògica cap amunt i deixa les fulles de l'arbre beneites. Un TargetaBicicleta que no sap d'on vénen les seves dades es pot col·locar en qualsevol pantalla, es pot provar amb dues línies i es pot redissenyar sense por.
Un matís honest: a la comunitat de React aquesta separació s'aplicava abans de manera molt estricta (es parlava de components «beneits» i «intel·ligents»). Amb els hooks, la línia s'ha tornat més difusa i avui es considera una guia, no una llei. Tot i així, preguntar-te «això pinta o això decideix?» continua sent una de les millors maneres d'aclarir un component confús.
- Organització de fitxers i convencions de noms
Amb cinc components qualsevol organització funciona. Amb cinquanta, no. Aquestes són les convencions que farem servir en tot el curs.
src/ ├── components/ │ ├── Benvinguda.jsx │ ├── Capcalera.jsx │ ├── EtiquetaEstat.jsx │ ├── LlistaBicicletes.jsx │ ├── PeuDePagina.jsx │ ├── TargetaBicicleta.jsx │ └── TargetaEstacio.jsx ├── dades/ │ └── domini.js ├── App.jsx ├── index.css └── main.jsx
Les regles, i el motiu de cadascuna:
| Regla | Exemple | Per què |
|---|---|---|
| Nom de component en PascalCase | TargetaBicicleta |
JSX distingeix components d'etiquetes HTML per la majúscula inicial (lliçó 01-03) |
| Un component per fitxer, amb el mateix nom | TargetaBicicleta.jsx |
Buscar el codi del que veus en pantalla és immediat |
Extensió .jsx si conté JSX |
Capcalera.jsx |
Deixa clar d'una ullada quins fitxers produeixen interfície; domini.js és .js perquè només té dades |
| Nom per rol, no per aspecte | EtiquetaEstat, no SpanVerd |
L'aspecte canvia; el paper que juga el component, molt menys |
| Noms en català, com la resta del domini | LlistaBicicletes |
Coherència amb el projecte; les APIs de React es queden en anglès |
Sobre l'estructura de carpetes hi ha dues escoles: per tipus (components/, dades/, hooks/) i per funcionalitat (cataleg/, reserves/, estacions/). Per a una aplicació petita com la nostra, la primera és més senzilla i és la que seguirem. Al Mòdul 11, quan CicloUrbano tingui diverses seccions, revisarem si val la pena migrar a la segona.
- Exportació per defecte enfront de l'exportació amb nom
Cada fitxer de component ha d'exportar alguna cosa perquè altres el puguin importar. Hi ha dues maneres, i convé entendre bé la diferència.
Exportació per defecte
// src/components/EtiquetaEstat.jsx
function EtiquetaEstat() {
return <span className="estat estat--disponible">disponible</span>;
}
export default EtiquetaEstat;// En importar-lo, el nom el tries tu (encara que no l'hauries de canviar)
import EtiquetaEstat from './components/EtiquetaEstat.jsx';Hi ha com a màxim una exportació per defecte per fitxer. És la convenció dominant a React per a «el component principal d'aquest fitxer».
Exportació amb nom
// src/dades/domini.js
export const bicicletes = [ /* ... */ ];
export const estacions = [ /* ... */ ];// En importar-les, els noms han de coincidir exactament i van entre claus
import { bicicletes, estacions } from '../dades/domini.js';N'hi pot haver tantes com vulguis per fitxer. És la manera natural quan un mòdul exposa diverses coses, com el nostre domini.js.
Comparativa
| Per defecte | Amb nom | |
|---|---|---|
| Sintaxi d'exportació | export default X; |
export const X = …; |
| Sintaxi d'importació | import X from '…' |
import { X } from '…' |
| Quantes per fitxer | Una | Diverses |
| Es pot reanomenar en importar? | Sí, lliurement | Sí, amb as: import { X as Y } |
| Autocompletat de l'editor | Pitjor: l'editor no coneix el nom | Millor: el nom és exacte |
| Detecció d'errates | Dolenta: import Targeta from './TargetaBicicleta.jsx' compila |
Bona: un nom inexistent dona error |
Convenció del curs: exportació per defecte per als components (un component per fitxer) i exportació amb nom per a dades i funcions auxiliars. És la barreja més estesa en projectes amb Vite i la que veuràs en la majoria del codi real.
- Compondre: muntar la pantalla completa
Escriurem els components nous i muntarem la pantalla. Recorda: les dades continuen escrites a mà dins de cada component, igual que a la lliçó 01-03.
EtiquetaEstat
// src/components/EtiquetaEstat.jsx
function EtiquetaEstat() {
return <span className="estat estat--disponible">disponible</span>;
}
export default EtiquetaEstat;Dues línies, i tot i així és un component legítim: concentra la decisió de com es representa un estat. Quan a la lliçó Props rebi l'estat des de fora, la classe estat--disponible passarà a calcular-se i aquest component serà l'únic lloc del projecte on aquesta regla existeixi.
Capcalera
// src/components/Capcalera.jsx
import Benvinguda from './Benvinguda.jsx';
function Capcalera() {
return (
<header className="capcalera">
<Benvinguda />
<nav className="capcalera__nav">
<ul>
<li>Catàleg</li>
<li>Estacions</li>
<li>Les meves reserves</li>
</ul>
</nav>
</header>
);
}
export default Capcalera;Aquí passa una cosa nova: un component que fa servir un altre component. Capcalera importa Benvinguda exactament igual que App la importava. No hi ha cap jerarquia especial: qualsevol component pot fer servir qualsevol altre que importi.
Com que Benvinguda ara viu dins d'un <header>, cal treure-li el propi perquè no s'imbriquin dues capçaleres, cosa que seria incorrecta semànticament:
// src/components/Benvinguda.jsx (ajustat)
function Benvinguda() {
return (
<div className="benvinguda">
<h1>CicloUrbano</h1>
<p>Lloga una bicicleta urbana al teu barri, per hores i sense complicacions.</p>
</div>
);
}
export default Benvinguda;Aquest ajust il·lustra una cosa que veuràs contínuament: els límits dels components es renegocien. Benvinguda va néixer com la capçalera sencera perquè no hi havia res més; ara que apareix la navegació, el seu paper es redueix al missatge de benvinguda i Capcalera assumeix el marc. Refactoritzar límits és feina normal, no un símptoma d'haver-ho fet malament.
LlistaBicicletes
// src/components/LlistaBicicletes.jsx
import TargetaBicicleta from './TargetaBicicleta.jsx';
function LlistaBicicletes() {
return (
<section className="llista-bicicletes">
<h2>Bicicletes disponibles</h2>
<TargetaBicicleta />
<TargetaBicicleta />
<TargetaBicicleta />
</section>
);
}
export default LlistaBicicletes;Aquest component és un contenidor en formació: avui només agrupa, però és la caixa preparada per rebre els filtres del Mòdul 3.
TargetaBicicleta, ara amb EtiquetaEstat a dins
// src/components/TargetaBicicleta.jsx
import EtiquetaEstat from './EtiquetaEstat.jsx';
function TargetaBicicleta() {
return (
<article className="targeta-bicicleta targeta-bicicleta--urbana">
<h3>
Urbana Clàssica <EtiquetaEstat />
</h3>
<p>Tipus: urbana</p>
<p>Estació: Plaça Major</p>
<p>
<strong>2,50 € / hora</strong>
</p>
</article>
);
}
export default TargetaBicicleta;Observa la classe targeta-bicicleta--urbana: la variant per tipus que vam fixar en el disseny de CicloUrbano. A la lliçó Estils deixarà d'estar escrita a mà i passarà a construir-se a partir del tipus.
App: el muntatge
// src/App.jsx
import Capcalera from './components/Capcalera.jsx';
import LlistaBicicletes from './components/LlistaBicicletes.jsx';
import PeuDePagina from './components/PeuDePagina.jsx';
function App() {
return (
<>
<Capcalera />
<main>
<LlistaBicicletes />
</main>
<PeuDePagina />
</>
);
}
export default App;Mira què ha passat amb App: s'ha quedat en tres línies de JSX que es llegeixen com un índex de la pantalla. Aquest és l'objectiu. Un component arrel que es llegeix com un esquema és el millor senyal que la descomposició està ben feta; un App.jsx de dues-centes línies és el senyal contrari.
Afegeix els estils de les peces noves a src/index.css:
/* Afegir al final de src/index.css */
.capcalera {
border-bottom: 1px solid #d9e2ec;
margin-bottom: 1.5rem;
}
.capcalera__nav ul {
display: flex;
gap: 1rem;
list-style: none;
padding: 0;
margin: 0 0 1rem;
color: #12805c;
font-weight: 600;
}
.llista-bicicletes {
margin-bottom: 2rem;
}
.estat {
display: inline-block;
padding: 0.15rem 0.6rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
vertical-align: middle;
color: #ffffff;
}
.estat--disponible { background-color: #12805c; }
.estat--alquilada { background-color: #b45309; }
.estat--mantenimiento { background-color: #9b1c1c; }
.targeta-bicicleta--urbana { border-left: 4px solid #12805c; }
.targeta-bicicleta--electrica { border-left: 4px solid #b45309; }
.targeta-bicicleta--carga { border-left: 4px solid #9b1c1c; }
- El límit que arrosseguem: les dades continuen fixes
Obre el navegador i veuràs la pantalla de l'esbós… amb tres bicicletes idèntiques, les tres «Urbana Clàssica, disponible, Plaça Major». L'estructura és correcta; les dades, no.
La causa és la mateixa que a la lliçó 01-03: cada component porta les seves dades escrites a dins. I això és exactament el contrari del que volem, perquè trenca el criteri de reutilització: un component les dades del qual estan a dins només serveix per mostrar aquestes dades.
flowchart LR
A["Avui: dades DINS del component<br/>3 instàncies = 3 targetes iguals"] --> B["Amb props: dades DES DE FORA<br/>3 instàncies = 3 bicicletes diferents"]
La peça que falta són les props, i és el contingut de la lliçó Props: Passant Dades als Components. Allà TargetaBicicleta rebrà una bicicleta del domini.js i les tres targetes mostraran per fi bici-001, bici-002 i bici-003. Pintar l'array complet sense escriure les targetes una a una arribarà una mica després, a Llistes i Claus.
Errors Comuns i Consells
- Crear components «per si de cas». Extreure
TitolSeccio,ParagrafGrisoContenidorFlexabans de tenir un problema real només afegeix indirecció. Extreu quan el component tingui un nom de domini evident o quan aparegui el segon ús. - Deixar que
App.jsxcreixi sense control. És l'abocador natural de l'aplicació. SiAppcomença a contenir marcatge detallat en lloc d'una llista de seccions, extreu aquest marcatge a un component. - Definir un component dins d'un altre. Escriure
function TargetaBicicleta() {…}dins del cos deLlistaBicicletescompila, però a cada render es crea una funció nova; per a la reconciliació que vas estudiar a 01-05 és un tipus diferent, així que destrueix i recrea el subarbre sencer i perd el seu estat. Defineix sempre els components al nivell superior del mòdul. - Anomenar per aspecte en lloc de per rol.
CaixaVerdadeixa de tenir sentit el dia que el disseny canvia a blau.EtiquetaEstatcontinua sent correcte passi el que passi amb la paleta. - Confondre l'arbre de components amb l'arbre del DOM.
Capcalerano genera cap etiqueta<capcalera>: genera el que hi ha al seureturn. Un component pot produir molts nodes, un o cap. - Consell: dibuixa l'arbre abans d'escriure codi. Cinc minuts amb un esbós i un retolador estalvien una tarda de reorganització. I compara'l després amb la pestanya Components de React DevTools.
- Consell: aplica la prova del nom. Si no aconsegueixes posar-li a un component un nom curt i descriptiu, el problema no és el nom: són els seus límits.
Exercicis
Exercici 1
L'aplicació de CicloUrbano necessita una pantalla de detall d'estació. L'esbós és aquest:
Plaça Major · Barri Centre 20 places · 12 lliures ──────────────────────────────── Bicicletes en aquesta estació [ targeta de bicicleta ] [ targeta de bicicleta ]
Identifica els components que faries servir, indica quins ja existeixen i quins caldria crear, i classifica cadascun com de presentació o contenidor. Justifica cada decisió amb un dels tres criteris de l'apartat 3.
Exercici 2
Un company ha escrit aquest component. Detecta els problemes de disseny i proposa una descomposició millor, sense escriure el codi complet: n'hi ha prou amb l'arbre resultant i el nom i la responsabilitat de cada peça.
// src/components/Tot.jsx
function Tot() {
return (
<div>
<h1>CicloUrbano</h1>
<p>Lloga una bicicleta urbana al teu barri…</p>
<div><span>Catàleg</span> <span>Estacions</span></div>
<h2>Bicicletes disponibles</h2>
<div className="targeta-bicicleta">
<h3>Urbana Clàssica <span className="estat estat--disponible">disponible</span></h3>
<p>2,50 € / hora</p>
</div>
<div className="targeta-bicicleta">
<h3>Elèctrica Pro <span className="estat estat--alquilada">llogada</span></h3>
<p>4,00 € / hora</p>
</div>
<footer><p>CicloUrbano — Servei de lloguer de bicicletes urbanes</p></footer>
</div>
);
}Exercici 3
Crea el component ResumFlota a src/components/ResumFlota.jsx. Ha de mostrar, dins d'una <section className="resum-flota">, un <h2> amb el text «Resum de la flota» i tres línies amb els totals de la flota de CicloUrbano segons el domini.js: total de bicicletes, disponibles i no disponibles. Escriu els números a mà (encara no sabem calcular-los a partir de les dades) i col·loca'l a App.jsx entre la capçalera i la llista. Després dibuixa l'arbre de components actualitzat.
Solucions
Solució 1.
| Component | Existeix? | Tipus | Criteri que ho justifica |
|---|---|---|---|
DetallEstacio |
Nou | Contenidor | Responsabilitat única: coordina la pantalla; és la caixa on viurà la lògica de l'estació |
TargetaEstacio |
Ja existeix (01-03) | Presentació | Reutilització: la capçalera amb nom, barri i places és la mateixa que al llistat d'estacions |
DisponibilitatEstacio |
Nou | Presentació | Responsabilitat única: «20 places · 12 lliures» és una informació amb regles pròpies que també apareixerà al mapa |
LlistaBicicletes |
Ja existeix | Contenidor | Reutilització: exactament el mateix bloc del catàleg, filtrat per estació |
TargetaBicicleta |
Ja existeix | Presentació | Reutilització: és el mateix component sense cap canvi |
EtiquetaEstat |
Ja existeix | Presentació | Reutilització: tercer ús del distintiu |
El rellevant de l'exercici és que quatre dels sis components ja estaven escrits. Això és el que es guanya amb uns límits ben traçats: la segona pantalla costa molt menys que la primera.
Solució 2.
Problemes de disseny:
- Sense responsabilitat única.
Totfa de capçalera, navegació, catàleg, targeta i peu alhora; la seva descripció necessitaria quatre «i». - Zero reutilització. El marcatge de la targeta està duplicat literalment, i el del distintiu d'estat també. Qualsevol canvi de disseny cal aplicar-lo dues vegades.
- Nom inútil.
Totno descriu cap responsabilitat, cosa que és el símptoma clàssic de límits mal traçats. - Marcatge no semàntic.
<div>per a les targetes i per a la navegació, en lloc de<article>i<nav>.
Descomposició proposada:
flowchart TD
APP[App] --> CAB[Capcalera]
APP --> LIS[LlistaBicicletes]
APP --> PIE[PeuDePagina]
CAB --> BIE[Benvinguda]
LIS --> T1[TargetaBicicleta]
LIS --> T2[TargetaBicicleta]
T1 --> E1[EtiquetaEstat]
T2 --> E2[EtiquetaEstat]
| Component | Responsabilitat |
|---|---|
App |
Muntar les tres zones de la pantalla |
Capcalera |
Identitat del lloc i navegació |
Benvinguda |
Títol i eslògan |
LlistaBicicletes |
Títol de la secció i conjunt de targetes |
TargetaBicicleta |
Dades d'una bicicleta |
EtiquetaEstat |
Distintiu visual de l'estat |
PeuDePagina |
Informació de tancament |
Solució 3.
// src/components/ResumFlota.jsx
function ResumFlota() {
return (
<section className="resum-flota">
<h2>Resum de la flota</h2>
<p>Total de bicicletes: 5</p>
<p>Disponibles: 3</p>
<p>No disponibles: 2</p>
</section>
);
}
export default ResumFlota;// src/App.jsx
import Capcalera from './components/Capcalera.jsx';
import ResumFlota from './components/ResumFlota.jsx';
import LlistaBicicletes from './components/LlistaBicicletes.jsx';
import PeuDePagina from './components/PeuDePagina.jsx';
function App() {
return (
<>
<Capcalera />
<main>
<ResumFlota />
<LlistaBicicletes />
</main>
<PeuDePagina />
</>
);
}
export default App;Arbre actualitzat:
flowchart TD
APP[App] --> CAB[Capcalera]
APP --> RES[ResumFlota]
APP --> LIS[LlistaBicicletes]
APP --> PIE[PeuDePagina]
CAB --> BIE[Benvinguda]
LIS --> T1[TargetaBicicleta]
LIS --> T2[TargetaBicicleta]
LIS --> T3[TargetaBicicleta]
T1 --> E1[EtiquetaEstat]
T2 --> E2[EtiquetaEstat]
T3 --> E3[EtiquetaEstat]
Els números «5, 3, 2» surten de comptar a mà el domini.js, i aquest és precisament el problema: si demà entra una bicicleta nova, el resum mentirà. Derivar aquests totals de les dades és qüestió d'una lliçó.
Conclusió
Un component és la unitat de disseny de React: encapsula marcatge, lògica i estil d'un tros d'interfície, i el seu valor depèn sobretot d'on traces els seus límits. Ara tens un mètode per traçar-los: partir de l'esbós, envoltar les zones amb nom propi i validar cada candidat contra tres criteris —responsabilitat única, reutilització i mida manejable—, evitant tant el component que ho fa tot com la fragmentació en peces trivials.
Has convertit l'esbós del catàleg de CicloUrbano en un arbre de components real: App munta Capcalera, LlistaBicicletes i PeuDePagina; Capcalera conté Benvinguda; LlistaBicicletes conté TargetaBicicleta, i aquesta conté EtiquetaEstat. Saps distingir components de presentació de components contenidors i fer servir aquesta distinció per empènyer la lògica cap amunt i deixar les fulles reutilitzables. I tens fixades les convencions que seguirà tot el curs: un component per fitxer a src/components/, PascalCase, extensió .jsx, exportació per defecte per als components i amb nom per a les dades.
També has vist el sostre amb què xoquem: l'estructura és correcta però les tres targetes són idèntiques, perquè les dades continuen escrites dins dels components.
Abans de trencar aquest sostre, hi ha una parada obligatòria. Tot el que has escrit són components de funció, però en qualsevol projecte React amb alguns anys de vida trobaràs components escrits amb classes: una altra sintaxi, amb this, render() i constructor. No escriuràs codi nou així, però sí que necessites saber llegir-lo. Aquest és el tema de la lliçó següent: Components Funcionals vs de Classe.
Curs de React
Mòdul 1: Introducció a React
- Què és React?
- Configuració de l'Entorn de Desenvolupament
- Hola Món amb React
- JSX: Extensió de Sintaxi de JavaScript
- Com Renderitza React: Virtual DOM i Reconciliació
Mòdul 2: Components de React
- Entendre els Components
- Components Funcionals vs de Classe
- Props: Passar Dades als Components
- State: Gestió de l'Estat del Component
- Estils en els Components: CSS, Mòduls i Utilitats
Mòdul 3: Treballar amb Esdeveniments
- Gestió d'Esdeveniments a React
- Renderitzat Condicional
- Llistes i Claus
- Formularis i Components Controlats
- Validació de Formularis i Components No Controlats
- Accessibilitat en Components Interactius
Mòdul 4: Conceptes Avançats de Components
- Elevar l'Estat
- Composició vs Herència
- Mètodes del Cicle de Vida de React
- Hooks: Introducció i Ús Bàsic
- Límits d'Error: Capturar Fallades a la Interfície
Mòdul 5: Hooks de React
- Hook useState
- Hook useEffect
- Hook useRef i Accés al DOM
- Hook useContext
- Hook useReducer
- Hooks Personalitzats
Mòdul 6: Enrutament a React
- Introducció a React Router
- Configuració de React Router
- Rutes Imbricades
- Navegació Programàtica
- Rutes Protegides i Control d'Accés
Mòdul 7: Gestió de l'Estat
- Introducció a la Gestió de l'Estat
- API de Context
- Redux: Introducció i Configuració
- Redux: Accions i Reductors
- Redux: Connectar-lo a React
- Estat del Servidor: Peticions, Memòria Cau i Sincronització
Mòdul 8: Optimització del Rendiment
- Tècniques d'Optimització del Rendiment a React
- Memoïtzació amb React.memo
- Hooks useMemo i useCallback
- Divisió de Codi i Càrrega Mandrosa
- Mesurar el Rendiment amb React DevTools Profiler
Mòdul 9: Proves a React
- Introducció a les Proves
- Proves Unitàries amb Jest
- Proves de Components amb React Testing Library
- Proves de Codi Asíncron i Simulació d'APIs
- Proves d'Extrem a Extrem amb Cypress
Mòdul 10: Temes Avançats
- Renderitzat al Servidor (SSR) amb Next.js
- Generació de Llocs Estàtics (SSG) amb Next.js
- Suspense i React Server Components
- TypeScript amb React
- React Native: Creació d'Aplicacions Mòbils
