Sergio Xalambrí
March 28, 2016

# Combinando React.js y Redux.js

Redux es especialmente bueno al usarlo con librerías como React ya que facilita usar React solo para la UI y dejar el estado en Redux.

Originally published at medium.com

En un artículo anterior vimos como funciona Redux.js y dijimos que era posible usarlo con cualquier framework o librería de JavaScript.

Y, aunque esto es cierto, Redux es especialmente bueno al usarlo con librerías como React.js, ya que podés describir tu UI como funciones puras y usar Redux para tener todo el estado de nuestra aplicación y pasarlo a nuestras vistas.

## Instalando react-redux

La conexión de React con Redux no esta incluida directamente en Redux, para esto necesitamos bajar react-redux, así que vamos a descargar lo necesario:

    npm i -S react react-dom react-redux redux

## Encapsulando la aplicación

Lo primero que necesitamos es encapsular nuestra aplicación con el componente `Provider` que trae `react-redux`. Este componente recibe un único parámetro llamado store el cual es, como su nombre indica, la instancia del Store que usamos.

    import React from "react";
    import { render } from "react-dom";
    import { Provider } from "react-redux";

    import store from "./store";
    import App from "./components/App";

    render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById("app")
    );

Este componente `Provider` define en el contexto global de React nuestra instancia del store.

## Accediendo al Store

Una vez encapsulada nuestra aplicación de React nos toca definir que componentes van a acceder a nuestro Store, ya que no todos lo van a necesitar.

Para hacer eso necesitamos conectar nuestros componentes a Redux, esto se logra con un decorador que trae `react-redux` llamado `connect`.

    // importamos el decorador @connect de react-redux
    import { connect } from "react-redux";
    import React from "react";
    import UserItem from "./UserItem";

    // aplicamos el decorador @connect a nuestro componente
    @connect()
    class UserList extends React.Component {
      render() {
        // renderizamos el listado de usuarios que
        // recibimos como props del Store
        return (
          <section>
            {this.props.users.map(user => (
              <UserItem {...user} key={user.id} />
            ))}
          </section>
        );
      }
    }
    export default UserList;

De esta forma nuestro componente UserList va a tener dentro de sus `props` todos los datos del Store. Con esto ya podemos renderizar nuestra aplicación usando los datos almacenados en el Store de Redux.

## Optimizando

Aunque el método anterior sea más que suficiente no es lo mejor a nivel de performance, ya que de esta forma cada vez que cambie algo del Store se va a volver a renderizar `UserList`, incluso si la lista de usuario no cambio.

Para mejorar esto el decorador `connect` puede recibir una función que define que datos pasar al componente conectado.

    function mapStateToProps(state, props) {
      // armamos un objeto solo con los
      // datos del store que nos interesan
      // y lo devolvemos
      return {
        users: state.users,
      };
    }

    // aplicamos el decorador @connect pasándole
    // nuestra función mapStateToProps
    @connect(mapStateToProps)
    class UserList extends React.Component {
      ...
    }

De esta forma podemos solo enviar a `UserList` el listado de usuarios, así cuando se modifique otra cosa que no sea la lista de usuarios no se va a volver a renderizar el componente.

## Despachando acciones

Entre las `props` que el decorador `connect` inyecta a nuestro componente la función `dispatch` del Store, con la cual podemos despachar acciones.

    // cargamos nuestro creador de acciones
    import sendData from '../actions/send-data';

    @connect()
    class UserList extends React.Component {
      handleSendData() {
        const action = sendData();
        // despachamos la acción al store
        this.props.dispatch(action);
      }
      ...
    }

Resulta que `connect` como segundo argumento podemos pasarle una función que nos permite controlar la función `dispatch` para mandar una personalizada.

    import sendData from '../actions/send-data';
    // importamos el método bindActionCreators de Redux
    import { bindActionCreators } from 'redux';

    function mapStateToProps(state, props) { ... }

    function mapDispatchToProps(dispatch, props) {
      // creamos un objeto con un método para crear
      // y despachar acciones fácilmente y en
      // una sola línea
      const actions = {
        sendData: bindActionCreators(sendData, dispatch),
      };

      // devolvemos nuestras funciones dispatch
      // y los props normales del componente
      return { actions };
    }

    // decoramos nuestro componente pasándole las
    // funciones mapStateToProps y mapDispatchToProps
    @connect(mapStateToProps, mapDispatchToProps)
    class UserList extends React.Component {
      handleSendData() {
        // creamos y despachamos la acción sendData
        this.props.actions.sendData();
      }
      ...
    }

De esta forma podemos mandar a nuestro componente las acciones que necesitamos y que con solo ejecutarlas ya haga el dispatch de estas.

## Funcionamiento sin decoradores

Aunque `connect` esta pensado como decorador es posible usarlo como una función normal sin necesidad de usar Babel con el plugin babel-plugin-transform-decorators-legacy para soportar decoradores de la siguiente forma.

    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(Component);

Como siempre `connect` recibe `mapStateToProps` y `mapDispatchToProps` como parámetros, solo que además devuelve una función que recibe el componente a conectar y nos devuelve el componente conectado, el cual simplemente exportamos y listo, conseguimos el mismo resultado que usándolo como un decorador.

Esto es util si no queremos usar decoradores todavía, ya que la actual propuesta es muy posible que cambie a futuro.

## Conectando componentes puros

Aunque lo normal es usar `connect` con componentes hechos con clases es completamente posible usarlo con componentes puros si hacemos uso del decorador como una función.

    import React from 'react';
    import { connect } from 'react-redux';
    function mapStateToProps(state, props) { ... }
    // el componente puro a conectar
    function UserItem(props) { ... }
    // exportamos el componente conectándolo gracias a connect
    export default connect(mapStateToProps)(UserItem);

Así podríamos crear toda nuestra aplicación solamente con componentes puros, sin necesidad de usar clases. Esto nos obligaría, de verdad, a mantener el estado de toda nuestra aplicación en Redux y dejar React para la UI.

## Conclusión

Integrar React y Redux es bastante simple y gracias a `connect` es muy fácil controlar que datos del Store le llegan a cada componente permitiendo una mejor performance y evitando renders innecesarios.