Italian (Italiano) translation by Cinzia Sgariglia (you can also view the original English article)
Questa è la terza parte della serie della Guida introduttiva a Redux e in questo tutorial, imparareremo a collegare uno store Redux con React. Redux è una libreria indipendente che funziona con tutti le popolari librerie front-end & framework. E funziona senza problemi con React grazie al suo approccio funzionale.
Non è necessario avere seguito le parti precedenti di questa serie per dare senso questo tutorial. Se siete qui per imparare a utilizzare React con Redux, potete fare un riepilogo veloce qui sotto e poi controllare il codice della parte precedente e iniziare da lì.
Riepilogo veloce
Nel primo post, abbiamo imparato a conoscere il flusso di lavoro di Redux e risposto alla domanda, perché Redux?. Abbiamo creato un'applicazione demo molto essenziale e vi abbiamo mostrato come le varie componenti di Redux — azioni, reducer e store — sono collegati.
Nel post precedente, abbiamo iniziato a costruire un'applicazione elenco di contatti che consente di aggiungere contatti e poi li visualizza in un elenco. Per la nostra lista di contatti è stato creato un archivio Redux e abbiamo aggiunto alcuni reducer e le azioni. Abbiamo tentato di spedire le azioni e recuperare il nuovo stato utilizzando metodi di archivio come store.dispatch()
e store.getState()
.
Entro la fine di questo articolo, imparerete
- la differenza tra i componenti del contenitore e i componenti della presentazione
- la libreria di react-redux
- come associare react e redux utilizzando
connect()
- come spedire le azioni utilizzando
mapDispatchToProps
- come recuperare lo stato utilizzando
mapStateToProps
Il codice del tutorial è disponibile su GitHub presso il repo react-redux-demo. Prendete il codice dal ramo v2 e utilizzatelo come punto di partenza per questo tutorial. Se siete curiosi di sapere come l'applicazione si presenta entro la fine di questo tutorial, provate il ramo v3. Iniziamo.
Progettare una gerarchia di componente: Smart vs componente smart vs componente dumb
Si tratta di un concetto che probabilmente avete sentito prima. Ma diamo una rapida occhiata alla differenza tra componenti smart e dumb. Ricordate che avevamo creato due cartelle distinte per i componenti, uno denominato containers/, e l'altro components/. Il vantaggio di questo approccio è che la logica di comportamento è separata dalla vista.
I componenti di presentazione sono detti dumb, perché sono preoccupati di come appaiono le cose. Essi sono disaccoppiati dalla logica di business dell'applicazione e ricevono i dati e i callback da un componente genitore esclusivamente tramite props. A loro non importa se l'applicazione è connessa a uno store Redux, se i dati provengono dallo stato locale del componente genitore.
I componenti del contenitore, d'altra parte, trattano la parte comportamentale e dovrebbero contenere del markup e stile DOM molto limitato. Passano i dati necessari per eseguire il rendering dei componenti dumb come props.
Ho trattato l'argomento in modo approfondito in un altro tutorial, Componenti Stateful vs componenti Stateless in React.
Continuando, andiamo a vedere come stiamo organizzando i nostri componenti.

I componenti di presentazione
Ecco i componenti di presentazione che useremo in questo tutorial.
components/AddContactForm.jsx
import React from 'react'; const AddContactForm = ({onInputChange, onFormSubmit}) => ( <form> <div className="form-group"> <label htmlFor="emailAddress">Email address</label> <input type="email" class="form-control" name="email" onChange={onInputChange} placeholder="name@example.com" /> </div> {/* Some code omitted for brevity */} <div className="form-group"> <label htmlFor="physicalAddress">Address</label> <textarea className="form-control" name="address" onChange={onInputChange} rows="3"></textarea> </div> <button type="submit" onClick={onFormSubmit} class="btn btn-primary"> Submit </button> </form> ) export default AddContactForm;
È un modulo HTML per aggiungere un nuovo contatto. Il componente riceve il callback onInputChange
e onFormSubmit
come props. L'evento onInputChange
viene generato quando cambia il valore di input e onFormSubmit
quando il modulo è stato inviato.
components/ContactList.jsx
const ContactList = (props) => { return( <ul className="list-group" id="contact-list"> {props.contactList.map( (contact) => <li key={contact.email} className="list-group-item"> <ContactCard contact = {contact}/> </li> )} </ul>) } export default ContactList;
Questo componente riceve un array di oggetti di contatto come props e da qui il nome ContactList. Utilizziamo il metodo Array.map()
per estrarre singoli dettagli di contatto e quindi trasmettere i dati al <ContactCard />
.
components/ContactCard.jsx
const ContactCard = ({contact}) => { return( <div> <div className="col-xs-4 col-sm-3"> {contact.photo !== undefined ? <img src={contact.photo} alt={contact.name} className="img-fluid rounded-circle" /> : <img src="img/profile_img.png" alt ={contact.name} className="img-fluid rounded-circle" />} </div> <div className="col-xs-8 col-sm-9"> <span className="name">{contact.name + ' ' + contact.surname}</span><br/> {/* Some code omitted for brevity */} </div> </div> ) } export default ContactCard;
Questo componente riceve un oggetto di contatto e visualizza il nome e l'immagine del contatto. Per le applicazioni pratiche, avrebbe senso ospitare le immagini JavaScript nel cloud.
I componenti del contenitore
Stiamo anche costruendo l'ossatura dei componenti del contenitore.
containers/Contacts.jsx
class Contacts extends Component { constructor(props) { super(props); this.returnContactList = this.returnContactList.bind(this); } returnContactList() { // Retrieve contactlist from the store } render() { return ( <div> <AddContact/> <br /> <ContactList contactList= {this.returnContactList()} /> </div> ); } } export default Contacts;
La funzione returnContactList()
recupera l'array degli oggetti di contatto e lo passa al componente ContactList. Poiché returnContactList()
recupera i dati dallo store, lasceremo quella logica in bianco per il momento.
containers/AddContacts.jsx
class AddContact extends Component { constructor(props) { super(props); /* Function binding goes here. Omitted for brevity */ } showAddContactBox() { /* Logic for toggling ContactForm */ } handleInputChange(event) { const target = event.target; const value = target.value; const name = target.name; /* Logic for handling Input Change */ } handleSubmit(e) { e.preventDefault(); /* Logic for hiding the form and update the state */ } /* Renders the AddContactForm */ renderForm() { return( <div className="col-sm-8 offset-sm-2"> <AddContactForm onFormSubmit={this.handleSubmit} onInputChange={this.handleInputChange} /> </div> ) } render() { return( <div> { /* A conditional statement goes here that checks whether the form should be displayed or not */} </div> ) } } export default AddContact;
Abbiamo creato tre ossature del metodo di gestione che corrisponde alle tre azioni. Tutte inviano le azioni per aggiornare lo stato. Nel metodo render, abbiamo lasciato fuori la logica per mostrare/nascondere il modulo perché abbiamo bisogno di recuperare lo stato.
Ora vediamo come associare react e redux insieme
La libreria di react-redux
I binding di di react non sono disponibili in Redux per impostazione predefinita. Sarà necessario installare innanzitutto una libreria supplementare chiamata react-redux.
npm install --save react-redux
La libreria esporta solo due API che è necessario ricordare, un componente <Provider />
e una funzione di ordine superiore conosciuta come connect()
.
Il componente Provider
Le librerie come Redux hanno bisogno di rendere accessibile lo store dei dati all'intero albero del componente react a partire dal componente principale. Il pattern Provider consente alla libreria di passare i dati dall'alto verso il basso. Il codice riportato di seguito dimostra come Provider aggiunge magicamente lo stato a tutti i componenti nell'albero dei componenti.
Codice demo
import { Provider } from 'react-redux' ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
L'intera applicazione deve poter accedere allo store. Così, avvolgiamo provider intorno al componente dell'app e quindi aggiungiamo i dati di cui abbiamo bisogno al contesto dell'albero. I discendenti del componente, quindi, hanno accesso ai dati.
Il metodo connect()
Ora che abbiamo messo a disposizione lo store alla nostra applicazione, abbiamo bisogno di collegare react con store. L'unico modo in cui è possibile comunicare con lo store è inviando azioni e recuperando lo stato. In precedenza abbiamo usato store.dispatch()
per inviare le azioni e store.getState()
per recuperare l'ultimo snapshot dello stato. connect()
vi permette di fare esattamente questo, ma con l'aiuto di due metodi denominati mapDispatchToProps
e mapStateToProps
. Ho dimostrato questo concetto nell'esempio che segue:
Codice demo
import {connect} from 'react-redux' const AddContact = ({newContact, addContact}) => { return ( <div> {newContact.name} <br /> {newContact.email} <br /> {newContact.phone} <br /> Are you sure you want to add this contact? <span onClick={addContact}> Yes </span> </div> ) } const mapStateToProps = state => { return { newContact : state.contacts.newContact } } const mapDispatchToProps = dispatch => { return { addContact : () => dispatch(addContact()) } } export default connect( mapStateToProps, mapDispatchToProps )(AddContact)
mapStateToProps
e mapDispatchToProps
restituiscono entrambi un oggetto e la chiave di questo oggetto diventa un prop del componente collegato. Per esempio, state.contacts.newContact
è mappata a props.newContact
. L'action creator addContact()
viene mappato a props.addContact
.
Ma a questo scopo, è necessaria l'ultima riga nel frammento di codice precedente.
export default connect( mapStateToProps, mapDispatchToProps )(AddContact)
Invece di esportare direttamente il componente AddContact
, stiamo esportando una componente connessa. La connessione fornisce addContact
e newContact
come props per il componente <AddContact />
.
Come connettere React e Redux?
Successivamente, copriremo i passaggi che dovete seguire per connettere React e Redux.
Installare la libreria di react-redux
Installare la libreria react-redux se non lo avete già fatto. È possibile utilizzare NPM o Yarn per installarlo.
npm install react-redux --save
Fornire store per il componente della vostra app
Create prima lo store. Quindi, rendete l'oggetto store accessibile all'albero del vostro componente facendolo passare come un prop a <Provider />
.
index.js
import React from 'react'; import {render}from 'react-dom'; import { Provider } from 'react-redux' import App from './App'; import configureStore from './store' const store = configureStore(); render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
Connettere i contenitori di React a Redux
La funzione di connessione viene utilizzata per l'associazione del contenitore di React a Redux. Ciò significa che è possibile utilizzare la funzionalità connetti per:
- sottoscrivere lo store e mappare il suo stato al vostro prop
- inviare le azioni e mappare i callback di dispatch nei vostri props
Una volta che avete collegato l'applicazione a Redux, è possibile utilizzare this.props
per accedere allo stato attuale e anche spedire le azioni. Ho intenzione di dimostrare il processo del componente AddContact
. AddContact
deve spedire tre azioni e ottenere lo stato di due proprietà dallo store. Diamo un'occhiata al codice.
In primo luogo, importate connect
in AddContact.jsx.
import { connect } from 'react-redux';
In secondo luogo, create due metodi mapStateToProps
e mapDispatchToProps
.
function mapStateToProps(state) { return { isHidden : state.ui.isAddContactFormHidden, newContact: state.contacts.newContact } } function mapDispatchToProps(dispatch) { return { onFormSubmit: (newContact) => { dispatch(addContact(newContact)); }, onInputChange: (name,value) => { dispatch(handleInputChange(name,value)); }, onToggle: () => { dispatch(toggleContactForm()); } } }
mapStateToProps
riceve lo stato dallo store come argomento. Restituisce un oggetto che descrive come lo stato dello store viene mappato nel vostro props. mapDispatchToProps
restituisce un oggetto simile che descrive come le azioni dispatch vengono mappate sul vostro props.
Infine, utilizziamo connect
per associare il componente AddContact
alle due funzioni come segue:
export default connect(mapStateToProps, mapDispatchToProps) (AddContact)
Aggiornare i componenti del contenitore per utilizzare i props
I props del componente sono ora in grado di leggere lo stato dallo store e dalle azioni dispatch. La logica per handleInputChange
, handleSubmit
e showAddContactBox
deve essere aggiornata come segue:
showAddContactBox() { const { onToggle } = this.props; onToggle(); } handleInputChange(event) { const target = event.target; const value = target.value; const name = target.name; const { onInputChange } = this.props; onInputChange(name,value); } handleSubmit(e) { e.preventDefault(); this.props.onToggle(); this.props.onFormSubmit(); }
Abbiamo definito i metodi dell'handler gestore. Ma c'è ancora una parte mancante — l'istruzione condizionale all'interno della funzione render
.
render() { return( <div> { this.props.isHidden === false ? this.renderForm(): <button onClick={this.showAddContactBox} className="btn"> Add Contact </button>} </div> ) }
Se isHidden
è false, il modulo viene eseguito. In caso contrario, viene mostrato un pulsante.
Visualizzare i contatti
Abbiamo completato la parte più impegnativa. Ora, tutto ciò che resta è visualizzare questi contatti come un elenco. Il contenitore Contacts
è il posto migliore per quella logica.
import React, { Component } from 'react'; import { connect } from 'react-redux'; /* Component import omitted for brevity */ class Contact extends Component { constructor(props) { super(props); this.returnContactList = this.returnContactList.bind(this); } returnContactList() { return this.props.contactList; } render() { return ( <div> <br /> <AddContact/> <br /> <ContactList contactList= {this.returnContactList()} /> </div> ); } } function mapStateToProps(state) { return { contactList : state.contacts.contactList, } } export default connect(mapStateToProps, null) (Contact);
Siamo passati attraverso la stessa procedura che abbiamo seguito sopra per collegare il componente Contacts con lo store Redux. La funzione mapStateToProps
mappa l'oggetto dello store ai props contactList
. Abbiamo poi usato connect per associare il valore di props al componente Contacts. Il secondo argomento di connect è null, perché non abbiamo le azioni da inviare. Ciò completa l'integrazione della nostra app con lo stato dello store Redux.
E adesso?
Nel prossimo post, daremo uno sguardo approfondito ai middlewares e avvieremo azioni dispatch che coinvolgano il recupero di dati dal server. Condividete le vostre riflessioni nei commenti!
Envato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post