Comenzando con reaccionar-redux

Hola mundo usando React Redux

Esta guía asume que ya ha instalado react, redux, react-router y react-redux y ha configurado react, redux y react-router. Si no lo ha hecho, por favor hágalo.

Nota: Si bien react-router no depende de react-redux, es muy probable que lo usemos en nuestra aplicación de reacción para el enrutamiento y esto hace que sea realmente fácil para nosotros usar react-redux .


NOMBRE DE ARCHIVO: app.js

'use strict';

import React from 'react';
import { render } from 'react-dom';
import { Router, Route, Link, browserHistory, IndexRoute } from 'react-router';
import { Provider } from 'react-redux';
import store from './stores';

render(
  (
    <Provider store={ store }>
      <Router history={ browserHistory }>
        {/* all the routes here */}
      </Router>
    </Provider>
  ),
  document.getElementById('app')
);

Este archivo tendrá sentido para la mayoría de ustedes. Lo que estamos haciendo aquí es obtener la tienda de ./stores y pasarla a todas las rutas usando Componente de orden superior Provider proporcionado por reaccionar-redux.

Esto hace que la tienda esté disponible en toda nuestra aplicación.


Ahora, consideremos este escenario. Tenemos un componente ‘UserComponent’ que obtiene los datos del reductor ‘usuario’ y tiene un botón que, cuando se hace clic, actualiza los datos en la tienda.

Estructura de la aplicación

Nuestro rootReducer tiene un reductor de usuario

const rootReducer = combineReducers({
    user: userReducer,
})
export default rootReducer;

Nuestro userReducer se ve así

const default_state = {
  users: [],
  current_user: {
    name: 'John Doe',
    email: '[email protected]',
    gender: 'Male'
  },
  etc: {}
};

function userReducer( state=default_state, action ) {

  if ( action.type === "UPDATE_CURRENT_USER_DATA" ) {
    return Object.assign( {}, state, { current_user: Object.assign( {}, state.current_user, { [action.payload.field]: action.payload.value } ) } );
  }
  else {
    return state;
  }

}

export default userReducer;

Y nuestro archivo actions se parece a esto

export function updateCurrentUserData( data ) {
  return {
    type: "UPDATE_CURRENT_USER_DATA",
    payload: data
  }
}

Finalmente, trabajemos en nuestro componente.

NOMBRE DE ARCHIVO: UserComponent.js

'use strict';

import React from 'react';
import { connect } from 'react-redux';
import * as Action from './actions';

let UserComponent = (props) => {

  let changeUserDetails = (field, value) => {
    // do nothing
  }

  return(
    <div>
      <h1>Hello { props.current_user.name }</h1>
      <p>Your email address is { props.current_user.email }</p>
      <div style={{ marginTop: 30 }}>
        <button onClick={ () => { changeUserDetails('name', 'Jame Smith') } }>Change Name</button>
        <button onClick={ () => { changeUserDetails('email', '[email protected]') } }>Change Email Address</button>
      </div>
    </div>
  )

}

export default UserComponent;

Por supuesto, esto no funcionará, ya que aún no lo hemos conectado a la tienda.

En caso de que te lo preguntes, este es un componente funcional sin estado, ya que estamos usando redux y realmente no necesitamos un estado interno para nuestro componente, este es el momento adecuado para usarlo.

El método connect proporcionado por react-redux toma tres parámetros

mapStateToProps, mapDispatchToProps y el Componente mismo.

conectar (mapStateToProps, mapDispatchToProps) (Componente)


Agreguemos conectar a nuestro componente UserComponent junto con mapStateToProps y mapDispatchToProps

Y también actualicemos nuestra función cambiarDetallesDeUsuario, de modo que cuando se le llame, enviará una acción a nuestros reductores y, según el tipo de acción, nuestro reductor se activará y realizará cambios en la tienda, y una vez que la tienda actualice react-redux volverá a renderizar nuestro componente con los nuevos datos.

¿Suena complicado? Realmente no lo es.

Nuestro UserComponent.js se verá como

'use strict';

import React from 'react';
import { connect } from 'react-redux';
import * as Action from './actions';

const mapStateToProps = ( state, ownProps ) => {
  return {
    current_user: state.user.current_user,
  }
}

const mapDispatchToProps = ( dispatch, ownProps ) => {
  return {
    updateCurrentUserData: (payload) => dispatch( Action.updateCurrentUserData(payload) ),
  }
}


let UserComponent = (props) => {

  let changeUserDetails = (field, value) => {
    props.updateCurrentUserData({ field: field, value: value });
  }

  return(
    <div>
      <h1>Hello { props.current_user.name }</h1>
      <p>Your email address is { props.current_user.email }</p>
      <div style={{ marginTop: 30 }}>
        <button onClick={ () => { changeUserDetails('name', 'Jame Smith') } }>Change Name</button>
        <button onClick={ () => { changeUserDetails('email', '[email protected]') } }>Change Email Address</button>
      </div>
    </div>
  )

}

const ConnectedUserComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(UserComponent)

export default ConnectedUserComponent;

Lo que hicimos aquí se agrega

  • mapStateToProps: Esto nos permite obtener los datos de la tienda y cuando esos datos cambien, nuestro componente se volverá a renderizar con los nuevos datos.

Nuestro componente solo se volverá a representar si los datos de nuestro componente solicitan cambios en la tienda y no cuando cualquier otro dato cambia en la tienda.

  • mapDispatchToProps: Esto nos permite enviar acciones a todos los reductores de nuestro componente… (podría ser cualquier componente), y según el tipo de acción, nuestro userReducer se activará y devolverá un nuevo estado con los datos actualizados.

  • ConnectedUserComponent: Por último, conectamos nuestro componente a la tienda usando el método connect pasando todos los parámetros y exportando el componente conectado.

  • También actualizamos nuestra función changeUserDetails para llamar a method en props y también pasar los datos. Y props a su vez envía el método que llamamos a todos los reductores.


NOTA:

  • Si no devolvemos un nuevo estado desde reducer, react-redux no volverá a renderizar nuestro componente.

Instalación o Configuración

Usar redux directamente con react puede parecer un poco difícil. En cuanto a cada componente que desee actualizar cuando cambie la tienda, debe suscribir ese componente a redux store

React Redux se encarga de todo esto y hace que sea muy fácil escribir componentes que puedan solicitar los datos que necesitan de redux store y recibir una notificación solo cuando esos datos cambien. Esto nos permite escribir componentes realmente efectivos.

Para instalar react-redux todo lo que tienes que hacer es ejecutar este comando npm

npm install --save react-redux

Y tu estas listo.


Nota: React Redux depende de

  • React (Versión 0.14 o posterior) y
  • Redux

Ejemplo completo

Supongamos que tenemos un contenedor “CustomersContainer” que conecta un componente tonto “Clientes” a la tienda Redux.

En index.js:

import { Component }, React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './redux/rootReducer';
import CustomersContainer from './containers/CustomersContainer';

let store = createStore(rootReducer);

render(
  <Provider store={store}>
    <CustomersContainer />
  </Provider>,
  document.getElementById('root')
);

En CustomersContainer:

import React, { Component } from 'react';
import { connect } from 'react-redux';

// Import action creators
import { fetchCustomers } from '../redux/actions';

// Import dumb component
import Customers from '../components/Customers';

// ES6 class declaration
class CustomersContainer extends Component {
  componentWillMount() {
    // Action fetchCustomers mapped to prop fetchCustomers
    this.props.fetchCustomers();
  }

  render() {
    return <Customers customers={this.props.customers} />;
  }
}

function mapStateToProps(state) {
  return {
    customers: state.customers
  };
}

// Here we use the shorthand notation for mapDispatchToProps
// it can be used when the props and action creators have the same name 
const CustomersContainer = connect(mapStateToProps, { fetchCustomers })(CustomersContainer);

export default CustomersContainer;