Redux in React

Maico Orazio
weBeetle
Published in
5 min readMar 31, 2021
Come collegare lo store di Redux con un’app React

In questo secondo articolo della guida su Redux parleremo di come collegare lo store di Redux con i componenti sviluppati in React.

Se vi siete persi il primo articolo su Redux, vi invito a leggerlo. Abbiamo parlato dell’architettura di Redux e approfondito cosa sono i reducers, lo store, le actions, le named constants e gli action creators.

Come riportato nella prima parte, Redux è indipendente dal framework frontend, ma esistono librerie che permettono di integrarlo con il tuo framework preferito. Dagli stessi autori di Redux, è stato sviluppato react-redux, progettato per lavorare con il modello dei componenti di React.

Redux ci consente di separare lo stato dell’applicazione da React, creando un archivio globale, lo store di Redux, che si trova ad un livello superiore dell’applicazione ed alimenta lo stato di tutti gli altri componenti. I componenti si aggiornano ogni volta che questo viene aggiornato con un minimo impatto sulle prestazioni.

Prima di iniziare a scrivere qualche riga di codice, è necessario installare la libreria tramite npm o yarn:

npm install react-redux
yarn add react-redux

La logica di interazione con lo store di Redux è gestita utilizzando dei componenti wrapper. Per rendere disponibile lo store di Redux ai componenti dell’applicazione React, abbiamo bisogno del componente Provider, che prende come props lo store di Redux e avvolge l’intera applicazione intervenendo sul componente di più alto livello nella gerarchia dei componenti dell’applicazione, quello cioè che rappresenta la root della nostra applicazione:

import { Provider } from "react-redux";render (
<Provider store={store}>
<App />
</Provider>
document.getElementById("root")
);

Il ruolo del componente Provider è unicamente quello di mettere a disposizione dei propri figli lo store creato tramite la funzione createStore.

Dopo aver reso disponibile lo store di Redux alla nostra applicazione React, possiamo connettere i componenti utilizzando la funzione connect() della libreria react-redux.

A seconda del caso d’uso prende i seguenti parametri, almeno uno è richiesto:

  • una funzione che mappa la parte di store utile al componente, che per convenzione chiameremo mapStateToProps
  • una funzione che mappa le actions necessarie al componente, che chiameremo mapDispatchToProps

La funzione mapStateToProps permette di collegare una parte dello store di Redux alle props del componente React, in modo che il componente abbia accesso alla parte esatta dello store di cui ha bisogno. Riceve lo stato corrente di Redux e restituisce un oggetto sulle cui proprietà sono mappati i valori dello stato rilevanti per il componente corrente.

La funzione mapDispatchToProps fa qualcosa di simile alla funzione mapStateToProps, ma per le actions. Collega le actions di Redux alle props del componente React, in questo modo il componente sarà in grado di inviare messaggi allo store (dispatch delle actions di Redux). Riceve come parametro la funzione dispatch() di Redux e restituisce un oggetto con dei metodi che interagiscono con lo stato di Redux

Esempio di React con Redux

Prendiamo come esercizio l’esempio del precedente articolo e creiamo un’applicazione in React:

npx create-react-app example-react-redux 

Installiamo le librerie redux e redux-react all’interno della nostra applicazione:

npm install redux
npm install react-redux

Modifichiamo il file src/index.js in modo da aggiungere la libreria all’applicazione e importiamo il componente Provider che avvolgerà, come puoi vedere dal codice riportato sotto, l’intera applicazione rendendola consapevole dell’intero store di Redux:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import './index.css';
import App from './components/App';
import { store } from "./store/index";

ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App/>
</Provider>
</React.StrictMode>,
document.getElementById('root')
);

Ora creiamo il componente App, utile a visualizzare l’elenco della attività salvate nello store di Redux.

// src/components/App.js
import List from "./List";

const App = () => {
return (
<div>
<h2>Elenco attività</h2>
<List />
</div>
)
}

export default App;

Collegamento con lo stato di Redux

Il componente che interagirà con la parte di store interessata, ovvero i todos, è List. Come abbiamo detto prima, utilizzeremo la funzione connect per collegare il componente List con Redux.

Poiché vogliamo che List ottenga l’elenco delle attività da visualizzare, collegheremo la parte dello store tramite la funzione mapStateToProps.

// src/components/List.js
import {connect} from "react-redux";

const mapStateToProps = state => {
return {todos: state.todos}
}

const ConnectedList = ({todos}) => (
<ul>
{todos.map((title,i) => (
<li key={i}>{title}</li>
))}
</ul>
)

const List = connect(mapStateToProps)(ConnectedList);

export default List;

Il componente ConnectedList riceve l’elenco delle attività nelle props, una copia di todos presente nello store di Redux.

Ricordo che lo stato in Redux viene prodotto dai reducers.

Infine il componente viene esportato come List: il risultato della connessione del componente stateless, senza stato, ConnectedList con lo store di Redux.

Collegamento con le actions di Redux

Il componente Form che creiamo, ha la funzione di aggiungere nuove attività alla nostra applicazione.

Definiamo un componente funzionale e utilizziamo gli Hooks di React per gestire lo stato locale del componente.

Il componente Form mantiene nello stato locale la stringa di input del modulo e riceve una action di Redux per aggiornare lo stato globale.

// src/components/Form.js
import { useState } from "react";
import { connect } from "react-redux";
import { addTodo } from "../store/actions";
const mapDispatchToProps = dispatch => {
return {
addTodo: todo => dispatch(addTodo(todo))
}
}

const ConnectedForm = (props) => {
const [value, setValue] = useState("");

const onChangeText = (e) => {
setValue(e.target.value)
}

const handleSubmit = (e) => {
e.preventDefault();
if (value.trim() === "") return;
props.addTodo(value);
setValue("");
}

return (
<form onSubmit={handleSubmit}>
<input type="text" name="todo-title" value="" placeholder="titolo attività" id="todo-title" onChange={onChangeText} />
<button type="submit">aggiungi</button>
</form>
)
}

const Form = connect(null, mapDispatchToProps)(ConnectedForm);

export default Form;

Abbiamo importato il file dove abbiamo definito le actions di Redux, che utilizzeremo per collegarle al componente tramite la funzione mapDispatchToProps.

La funzione handleSubmit salva il testo scritto nell’input del modulo, inviando la action addTodo.

Infine il componente viene esportato come Form: il risultato della connessione del componente funzionale ConnectedForm con lo store di Redux.

Notate: il primo argomento della funzione connect deve essere null perché mapStateToProps è assente come nel nostro esempio, altrimenti si ottiene un errore dall’applicazione.

Aggiungiamo il componente Form all’applicazione e verifichiamo il risultato:

// src/components/App.js
import List from "./List";
import Form from "./Form";

const App = () => {
return (
<div>
<h2>Elenco attività</h2>
<List />
<Form />
</div>
)
}

export default App;

Viene eseguito nuovamente il rendering del componente List collegato allo store di Redux, ogni volta che aggiungi una nuova attività.

Conclusioni

Sebbene sia abbastanza semplice il collegamento tra componenti React e lo store di Redux, occorre evitare di connettere ogni componente della nostra applicazione. Uno dei principali motivi riguarda l’efficienza del rendering.

Per sfruttare al massimo le funzionalità di Redux occorre effettuare un’attenta analisi dei tipi di componenti che costituiscono la nostra applicazione e suddividerli in quelli che dovranno presentare i dati e consentire all’utente di interagire con essi, e quelli che faranno solo da contenitore dei primi componenti.

Soltanto i componenti contenitori dovrebbero essere connessi allo store di Redux, i quali tramite le props propagheranno le variazioni di stato agli altri componenti.

Questo consente di ottenere il massimo dal connubio di Redux con React.

--

--

Maico Orazio
weBeetle

Senior Web Application Developer. I'm a software engineer, a passionate coder, and a web developer. I am a fan of technology. #php #symfony #javascript #reactjs