# Combinando React.js y Redux.js

En un
[artículo anterior vimos como funciona Redux.js](https://sergiodxa.com/articles/introduccion-a-redux)
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](https://platzi.com/react/), 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:

```bash
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.

```js
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`.

```js
// 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.

```js
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.

```js
// 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.

```js
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](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy)
para soportar decoradores de la siguiente forma.

```js
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.

```js
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.