Componenten en Props

Met componenten splits je de UI in onafhankelijke, herbruikbare delen. Ook kun je over elk deel apart nadenken. Deze pagina introduceert het concept van componenten. Je vindt hier de volledige component API referentie

Conceptueel zijn componenten hetzelfde als JavaScript functies. Ze accepteren willekeurige invoerwaarden (deze noemen we “props”) en geven React elementen terug die beschrijven wat er op het scherm moet verschijnen.

Functie En Class Componenten

Een JavaScript functie is de eenvoudigste manier om een component te definiëren:

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

Deze functie is een geldig React component omdat ze een enkel “props” (dit is een verkorte vorm van “properties”) object argument met data krijgt en een React element terug geeft. We noemen dit soort componenten “functie componenten” omdat ze letterlijk JavaScript functies zijn.

Je kunt ook een ES6 class gebruiken om een component te definiëren:

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

De twee bovenstaande componenten zijn gelijkwaardig vanuit Reacts oogpunt.

Classes hebben wat extra features die we zullen bespreken in de volgende hoofdstukken. Tot die tijd zullen we functie componenten gebruiken omdat ze beknopter zijn.

Een Component Renderen

Tot nu toe hebben we alleen React elementen gezien die een DOM tag voorstellen:

const element = <div />;

Maar elementen kunnen ook componenten vertegenwoordigen die door de gebruiker gedefinieerd zijn:

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

Als React een element ziet, dat een door de gebruiker gedefinieerd component voorstelt, dan worden de JSX attributen doorgegeven aan deze component als een enkel object. We noemen dit object “props”.

Deze code toont bijvoorbeeld “Hello, Sara” op de pagina:

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

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

Probeer het op CodePen

Laten we samenvatten wat er gebeurt in dit voorbeeld:

  1. We roepen ReactDOM.render() aan met het` element.
  2. React roept het Welcome component aan met {name: 'Sara'} als de props.
  3. Onze Welcome component geeft een <h1>Hello, Sara</h1> element terug als resultaat.
  4. Het React DOM werkt efficiënt het DOM bij zodat het <h1>Hello, Sara</h1> bevat.

Opmerking: Begin component namen altijd met een hoofdletter.

React ziet componenten die met een kleine letter beginnen als DOM tags. <div /> is bijvoorbeeld een HTML div tag, maar <Welcome /> is een component en heeft Welcome nodig in de scope.

Om meer te leren over de redenen achter deze conventie, kun je JSX Uitgediept lezen.

Components Samenstellen

Componenten kunnen andere componenten gebruiken in hun uitvoer. Hierdoor kunnen we dezelfde component abstractie gebruiken voor elk detailniveau. Een knop, een formulier, een dialoog, een scherm: in React applicaties worden deze gewoonlijk allemaal uitgedrukt als componenten.

We kunnen bijvoorbeeld een App component maken die heel vaak Welcome op het scherm toont:

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

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

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

Probeer het op CodePen

Normaal gesproken hebben React applicaties helemaal bovenin een enkele App component. Als je React echter integreert in een bestaande applicatie, kan het zijn dat je van onderaf begint met een kleine component, zoals een Button, en dan langzaam naar boven werkt in de view hiërarchie.

Componenten Opsplitsen

Wees niet bang om componenten te splitsen in kleinere componenten.

Neem bijvoorbeeld dit Comment component:

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>
  );
}

Probeer het op CodePen

Het accepteert author (een object), text (een string) en date (een datum) als props en beschrijft een reactie op een social media website.

Het kan lastig zijn om deze component te veranderen door de gelaagdheid en het is ook lastig om indivuele delen ervan te hergebruiken. Laten we er een paar componenten uit halen.

Als eerste gaan we Avatar eruit halen:

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

De Avatar hoeft niet te weten dat hij binnen een Comment wordt getoond. Daarom hebben we zijn prop een generieke naam, user gegeven, in plaats van author.

We raden aan om props een naam te geven vanuit het oogpunt van de component, in plaats van de context waarin de component gebruikt wordt.

We kunnen het Comment nu een beetje vereenvoudigen:

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>
  );
}

Vervolgens extraheren we een UserInfo component, die een Avatar en de naam van de gebruiker naast elkaar rendert:

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

Hierdoor kunnen we Comment nog verder vereenvoudigen:

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>
  );
}

Probeer het op CodePen

Componenten extraheren lijkt misschien zwaar werk in het begin, maar een palet van herbruikbare componenten is de moeite waard in grotere applicaties. Een goede vuistregel is: als een deel van je UI vaker gebruikt wordt (Button, Panel, Avatar) of complex genoeg is van zichzelf (App, FeedStory, Comment), dan is het een goede kandidaat voor een herbruikbare component.

Props Zijn Read-Only

Of je een component nu als een functie of een class definieert, hij mag nooit zijn eigen props wijzigen. Neem bijvoorbeeld deze sum functie:

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

Dit soort functies worden “pure” genoemd, omdat ze niet proberen om hun invoerwaarden te wijzigen en altijd hetzelfde resultaat terug geven voor dezelfde invoerwaarden.

In tegenstelling hiermee is deze functie niet pure omdat ze haar eigen invoerwaarden aanpast:

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

React is behoorlijk flexibel, maar heeft een enkele strikte regel:

Alle React componenten moeten zich als pure functies gedragen ten opzichte van hun props.

Natuurlijk zijn applicatie UIs dynamisch en veranderen ze in de loop der tijd. In het volgende hoofdstuk zullen we het concept van “state” introduceren. Met state kunnen React componenten hun uitvoer in de loop der tijd wijzigen als reactie op acties van de gebruiker, netwerk reacties en andere acties, zonder deze regel te overtreden.