Components i propietats

Els components permeten separar la interfície d’usuari en peces independents, reutilitzables i pensar en cada peça de forma aïllada. Aquesta pàgina proporciona una introducció a la idea de components. Pots trobar una API detallada sobre components aquí.

Conceptualment, els components són com les funcions de JavaScript. Accepten entrades arbitràries (anomenades “props”) i retornen elements React que descriuen el que ha d’aparèixer a la pantalla.

Components funcionals i de classe

La forma més senzilla de definir un component és escriure una funció de JavaScript:

function Welcome(props) {
  return <h1>Hola, {props.name}</h1>;
}

Aquesta funció és un component de React vàlid perquè accepta un sol argument d’objecte “props” (que prové de propietats) amb dades i retorna un element de React. Anomenem aquests components “funcionals” perquè literalment són funcions JavaScript.

També pots utilitzar una classe d’ES6 per definir un component:

class Welcome extends React.Component {
  render() {
    return <h1>Hola, {this.props.name}</h1>;
  }
}

Els dos components anteriors són equivalents des del punt de vista de React.

Les classes tenen algunes característiques addicionals que veurem en les pròximes seccions. Fins llavors, farem servir components funcionals per la seva brevetat.

Renderitzant un component

Fins ara, només hem vist elements de React que representen etiquetes del DOM:

const element = <div />;

No obstant això, els elements també poden representar components definits per l’usuari:

const element = <Welcome name="Sara" />;

Quan React veu un element representant un component definit per l’usuari, passa els atributs JSX a aquest component com un sol objecte. Anomenem a aquest objecte “props”.

Per exemple, aquest codi mostra “Hola, Sara” a la pàgina:

function Welcome(props) {
  return <h1>Hola, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Prova-ho a CodePen

Recapitulem el que succeeix en aquest exemple:

  1. Fem una crida a ReactDOM.render() amb l’element <Welcome name="Sara"/>.
  2. React crida al component Welcome amb {name: 'Sara'} com “props”.
  3. El nostre component Welcome retorna un element <h1>Hola, Sara</h1> com a resultat.
  4. React DOM actualitza eficientment el DOM perquè coincideixi amb <h1>Hola, Sara</h1>.

Nota: Comença sempre els noms de components amb una lletra majúscula.

React tracta els components que comencen amb lletres minúscules com etiquetes del DOM. Per exemple, <div /> representa una etiqueta div HTML però <Welcome /> representa un component i requereix que Welcome estigui definit.

Per saber més sobre el raonament darrere d’aquesta convenció, pots consultar JSX en profunditat.

Composició de components

Els components poden referir-se a altres components en el seu interior. Això ens permet utilitzar la mateixa abstracció de component per a qualsevol nivell de detall. Un botó, un quadre de diàleg, un formulari, una pantalla: en aplicacions de React, tots són expressats comunament com a components.

Per exemple, podem crear un component App que renderitza Welcome moltes vegades:

function Welcome(props) {
  return <h1>Hola, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

Prova-ho a CodePen

En general, les aplicacions de React noves tenen un únic component App al capdamunt. No obstant això, si s’integra React en una aplicació existent, es podria començar de baix cap a dalt amb un petit component com Button i a poc a poc fer camí cap al cim de la jerarquia de la vista.

Extracció de components

No tinguis por de dividir els components en altres més petits.

Per exemple, considera aquest component Comment:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
        src={props.author.avatarUrl}
        alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Prova-ho a CodePen

Accepta author (un objecte), text (una cadena), i date (una data) com props, i descriu un comentari en una web de xarxes socials.

Aquest component pot ser difícil de canviar a causa de tota la nidificació, i també és difícil reutilitzar parts individuals d’ell. Extraiem alguns components d’aquest.

Primer, extraiem Avatar:

function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}

L’Avatar no necessita saber que està sent renderitzat dins d’un Comment. Aquest és el motiu pel qual li donem a la seva propietat un nom més genèric: user en comptes de author.

Recomanem anomenar les props des del punt de vista del component, en comptes del context en què s’utilitza.

Ara podem simplificar Comment una miqueta:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <Avatar user={props.author} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

A continuació, extraurem el component UserInfo que renderitza un Avatar al costat del nom de l’usuari:

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}

Això ens permet simplificar Comment encara més:

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Prova-ho a CodePen

Extreure components pot semblar una feina pesada al principi, però tenir una paleta de components reutilitzables val la pena en aplicacions més grans. Una bona regla en general és que si una part de la interfície d’usuari es fa servir diverses vegades (Button, Panel o Avatar), o és prou complexa per si mateixa (App, FeedStory, Comment), és bon candidat per ser un component reutilitzable.

Les props són només de lectura

Tant si declares un component, com una funció o com una classe, aquest mai ha de modificar les seves props. Considera aquesta funció sum:

function sum(a, b) {
  return a + b;
}

Aquestes funcions són anomenades “pures” perquè no intenten canviar les seves entrades, i sempre tornen el mateix resultat per a les mateixes entrades.

En contrast, aquesta funció és impura perquè canvia la seva pròpia entrada:

function withdraw(account, amount) {
  account.total -= amount;
}

React és bastant flexible però té una sola regla estricta:

Tots els components de React han d’actuar com a funcions pures pel que fa a les seves props.

Per descomptat, les interfícies d’usuari de les aplicacions són dinàmiques i canvien amb el temps. A la següent secció, introduirem un nou concepte d‘“estat”. L’estat permet als components de React canviar la seva sortida al llarg del temps en resposta a accions de l’usuari, respostes de xarxa i qualsevol altra cosa, sense violar aquesta regla.