Componenti presentational e container nei framework frontend

di Morgan Pizzini, in HTML5, JavaScript,

Nell'articolo https://www.html5italia.com/articoli/frontend/confronto-react-angular-svelte-vue.aspx abbiamo parlato dei principali framework o librerie, attualmente presenti sul mercato, che potremmo prendere in considerazione per lo sviluppo di una applicazione front-end. In questo script aggiungeremo un tassello che potremmo definire fondamentale in termini architetturali: andremo a creare un'architettura definita "Presentational e Container components". Tale sistema è utile, all'interno delle applicazioni front-end a suddividere i componenti che eseguono operazioni sui dati da quelli incaricati di mostrare un'interfaccia utente. Per fare un paragone con il mondo back-end, stiamo creando due sotto-categorie di componenti, una che si occuperà del Presentation Layer e una che gestirà la Business Logic.

Benchè questo livello di dettaglio non è richiesto da nessuno dei framework trattati, è bensì utile a noi sviluppatori, in quanto ci consente di creare dei componenti UI riutilizzabili al 100%, le cui uniche dipendenze sono i valori ricevuti come input. Allo stesso modo avere dei componenti che gestiscano tutte le chiamate ai servizi, o la trasformazione dei dati, prima di essere presentati a monitor.

In questo script andremo ad analizzare come condividere i dati verso il presentational component e come notificare il container riguardo un'azione effettuata dall'utente. In tutti gli esempi presenteremo una lista di elementi e un bottone, che a seguito di un click, invia al container una stringa "Ciao Mondo!".

Presentational e container in Angular


La comunicazione tra componenti, in Angular, viene effettuata tramite le direttive Input e Output. Partiamo con il preparare un componente che generi una lista e predisponga un metodo per gestire un evento emanato dal componente che andrà a presentare

import { Component } from "@angular/core";

@Component({
  selector: "my-app",
  template: `<component-one [list]="list" (evnt)="handle($event)"></component-one>`
})
export class AppComponent {
  list: number[] = [1, 2, 3, 4];
  handle(e) {
    console.log(e);
  }
}

Continuiamo con la creazione del componente di UI in modo tale che accetti come input una proprietà list ed emetta un evento tramite evnt

import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'component-one',
  template: `<ul>      <li <i>ngFor="let item of list">{{item}}</li>
    </ul>
    <button (click)="btnClick()">Click</button>`,
})
export class HelloComponent  {
  @Input() list: number[];
  @Output() evnt: EventEmitter<string> = new EventEmitter();

  btnClick(){
    this.evnt.emit('Ciao Mondo!');
  }
}

Presentational e container in React


Con React la condivisione di variabili ed eventi è semplicemente gestita da normali variabili o funzioni, senza la necessità di alcuna direttiva che specifichi i parametri in input o output tra i componenti.
Il container sarà così strutturato

import React, { useState } from 'react';
import Component from "./Component"

export default function App() {
  const [state, setState] = useState([1,2,3,4]);
  function handle(e){
    console.log(e);
  }
  return (
    <div>
      <Component list={state} evnt={handle}></Component>
    </div>
  );
}

A seguito dell'import di Component stabiliamo che la proprietà in input sarà passata attraverso il nome di list e l'output sarà collezionato da evnt che chiamerà la funzione handle. Prestando attenzione a mantenere gli stessi nomi, andiamo a creare il presentational component, utilizzando la variabile props come aggregatore dei parametri provenienti dal container component

export default function Component(props) {
  function btnClick() {
    props.evnt('Ciao Mondo!')
  };
  return (
    <div>
      <ul>        {props.list.map((value, index) => {
          return <li key={index}>{value}</li>
        })}
      </ul>
      <button onClick={btnClick}>
        Click
      </button>
    </div>
  );
}

Presentational e container in Vue


Iniziando sempre dal container, sapendo che la sintassi di Vue somiglia molto a quella di React, possiamo convertire il codice che abbiamo scritto in precedenza. L'unica accortezza da seguire è l'utilizzo degli attributi v-bind e v-on all'interno dell'HTML: la sintassi che trovavamo in React, trascritta in Vue, permette solo il passaggio di stringhe, per oggetti complessi è necessario usare degli attributi specifici

<template>
  <div id="app">
    <Component v-bind:list="list"  v-on:evnt="handle"/>
  </div>
</template>
<script>
import Component from './Component.vue'

export default {
  name: 'App',
  components: {
    Component
  },
  data: ()=>({
    list: [1,2,3,4]
  }),
  methods: {
    handle: function (e) {
      console.log(e)
    }
  }
}
</script>

La stessa procedura può essere applicata anche al presentational component, prestando attenzione a dichiarare i parametri in input in maniera esplicita all'interno della proprietà props. Per emettere un evento, invece, non occorrerà specificare nulla, in quanto è già disponibile in ogni componente Vue il metodo $emit che consente, fornendo un nome e opzionalmente dei parametri, di emettere appunto eventi.

<template>
  <ul v-for="item in list">
    {{item}}
  </ul>
  <button v-on:click="btnClick">
    Click
  </button>
</template>

<script>
export default {
  name: 'Component',
  props: ['list'],
  methods: {
     btnClick: function (e) {
      this.$emit('evnt', 'Ciao Mondo!')
    }
  }
}
</script>

Il codice scritto in Vue rispetta le aspettative: richiede meno architettura dell'esempio in Angular: non avendo alcuna tipizzazione per variabili in input e addirittura nessun parametro per l'output. Allo stesso tempo, l'utilizzo di props, e la differenziazione tra gli attributi HTML, porta ad avere un livello di controllo maggiore rispetto a React

Presentational e container in Svelte


Dall'introduzione a Svelte, fatta nell'articolo precedente, possiamo aspettarci solo semplicità e velocità di scrittura. Il container avrà la struttura seguente

<script>
import Component from './Component.svelte';
let list = [1,2,3,4];
function handle(e){
    console.log(e.detail)
}
</script>
<Component on:evnt={handle} list={list}/>

Le parti su cui porre la nostra attenzione sono quelle riguardanti la gestione degli eventi. Se infatti il passaggio di parametri ricorda molto React, per gli eventi è necessario utilizzare l'attributo on:nome-evento, per recuperare poi il valore emesso dobbiamo utilizzare la proprietà detail presente nell'evento ricevuto nel metodo come input.

Anche per il presentation component la sintassi risulta molto pulita, eccezion fatta per gli eventi, anche in questo caso abbiamo la necessità di scrivere alcune righe di codice per creare un generatore di eventi tramite la funzione createEventDispatcher.

<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();

export let list;
function btnClick() {
    dispatch('evnt', 'Ciao Mondo!');
}
</script>

<ul>{#each list as item}
    <li>{item}</li>
{/each}
</ul>
<button on:click={btnClick}>Click</button>

Ora che sappiamo come collegare i componenti all'interno della pagina, nei prossimi script vedremo come collegare più pagine e recuperare dati provenienti da REST API.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi