style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

React useReducer

Cuando queremos manejar estado mas complejo que una sola variable, o que depende muchas condiciones antes de entregar el valor final. Es mejor usar useReducer, este hook es sumamente similar a Redux y como tal es un observer de estado al que podemos subscribir nuestro componente.

Redux no es igual a Hooks o al revés useReducer no es Redux, hay importantes consideraciones de diseño al momento de querer reemplazar redux con hooks, eso lo veremos después cuando presentemos algo mas complejo que un simple contador, de momento vamos a expandir nuestro contador.

El nuevo contador

El nuevo contador nos permitirá incrementar o reducir su valor a voluntad. Solo tiene dos botones a continuación presento el código

import React, { useReducer } from 'react';
import R_merge from 'ramda/src/merge';
import ReactDOM from 'react-dom';

type Action =
  | { type: 'increment' }
  | { type: 'decrement' };

interface State {
  count: number
}

const reducer = (state: State, action: Action) => {
  switch (action.type) {
    case 'increment':
      return R_merge(state, { count: state.count + 1 });
    case 'decrement':
      return R_merge(state, { count: state.count - 1 });
    default:
      return state;
  }
}

const initialState: State = { count: 0 };

const Hello: React.SFC<{
  text: string
}> = props => {
  const [state, dispatch] = useReducer(reducer, initialState);

  const masAction = () => dispatch({ type: 'increment' });

  const menosAction = () => dispatch({ type: 'decrement' });

  return (
    <React.Fragment>
      <h1>Hello, {state.count}</h1>
      <button onClick={masAction}>Mas</button>
      <button onClick={menosAction}>Menos</button>
    </React.Fragment>
  );
};

ReactDOM.render(<Hello text="Javamexico"/>, document.getElementById('app'));

Como puedes ver es muy muy muy parecido a Redux, pero no es un estado global, es un estado para el componente que tenemos en este caso Hello, solo tenemos dos acciones llamadas increment y decrement. Estas las asignamos a los botones específicos. Nada complejo, también podemos ver que estamos usando typescript por lo que hay que definir los tipos, como no se muy bien typescript les dejo el link en el que me base: https://medium.com/@jrwebdev/react-hooks-in-typescript-88fce7001d0d. esto para que uds. puedan hacer las modificaciones que mas les gusten.

Si pero no

Una de las razones por las que considero que no cometo tantos errores (al menos no como antes con jQuery, backbone y similares) es que trato de hacer lo mas posible immutables mis colecciones, de modo que no tenga side effects inesperados, algo que ni typescript tiene, por lo que yo siempre uso una librería llamada Ramda; es como underscore pero 100% funcional e immutable sin crear wrappers como en immutable.js.

Sigo sin ver la utilidad de typescript, mas allá de documentar los tipos que también se puede hacer con jsdoc y si usas un editor que soporte jsdoc funciona exactamente igual que typescript, por lo tanto este es el ultimo código creado en typescript, como bien escribi anteriormente para encontrar errores nada como pruebas de unidad.

Les dejo el mismo componente pero en ES6, con los estilos de codificación que normalmente uso:

import React, { useReducer } from 'react';
import R_merge from 'ramda/src/merge';
import ReactDOM from 'react-dom';

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

const reducer = (state, action) => {
  switch (action.type) {
    case INCREMENT:
      return R_merge(state, { count: state.count + 1 });
    case DECREMENT:
      return R_merge(state, { count: state.count - 1 });
    default:
      return state;
  }
}

const initialState = { count: 0 };

const Hello = props => {
  const [state, dispatch] = useReducer(reducer, initialState);

  const masAction = () => dispatch({ type: INCREMENT });

  const menosAction = () => dispatch({ type: DECREMENT });

  return (
    <React.Fragment>
      <h1>Hello, {state.count}</h1>
      <button onClick={masAction}>Mas</button>
      <button onClick={menosAction}>Menos</button>
    </React.Fragment>
  );
};

ReactDOM.render(<Hello text="Javamexico"/>, document.getElementById('app'));

Las diferencias son mínimas, pero el resultado es el mismo.

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">