React Hooks – Tutorial

0
3474
Título del tutorial

Este tutorial es una introducción a los React Hooks. La API de Hooks ofrece una alternativa a las clases totalmente compatible. Se incluyen ejemplos de useState, useEffect y useContext.

Dependencias

  • React 16.12.0
  • Typescript 3.7.2

Índice

¿Qué es un Hook?

Los Hooks son una API que nos permite usar estado y otras características en un componente funcional.
Hasta la introducción de Hooks, los componentes funcionales no podían tener estado, se utilizaban principalmente para:
  • Componentes simples sin estado.
  • Estilos reutilizables.

 

Con la API de Hooks, los componentes funcionales pasan a tener el mismo potencial que los componentes de clases. Y de manera más declarativa y escueta.

useState

useState  es un Hook que nos permite guardar y modificar un estado en un componente funcional. El estado de un componente funcional se mantiene vivo entre las ejecuciones de este.
Gráfico que muestra el contexto que mantiene el estado de un componente funcional.
En el siguiente ejemplo se muestra un componente que cuenta cuántas veces se pulsa un botón.
import React, { useState } from "react";

interface Props {
  initial: number;
}

export const ClickCounter: React.FC<Props> = props => {
  const [counter, setCounter] = useState <number>(props.initial); // (A)

  const onClick = () => {
    setCounter(counter + 1); // (B)
  };

  return (
    <>
      <p>You have clicked {counter} times</p>
      <button onClick={onClick}>Click me</button>
    </>
  );
};
En (A)  se está declarando el estado utilizado para contar las pulsaciones.
useState es una función que recibe un parámetro. Este es el valor inicial del estado.
useState devuelve un Array con dos posiciones:
  • La primera es el valor actual del estado. Se actualiza automáticamente cuando cambie.
  • La segunda es una función que permite modificar el estado.

 

Al devolver un Array nos permite renombrar fácilmente los valores devueltos. Tanto como el estado como la función de modificación pueden tener cualquier nombre. Si devolviese un objeto, renombrar los valores sería más engorroso.

En (B)  se está utilizando la función que modifica el estado.
Siempre que el estado de un componente funcional cambia, este se ejecuta de nuevo.

Gráfico que muestra el ciclo de ejecución de un componente funcional con Hooks

Creando un Hook propio

Uno de los objetivos principales de los Hooks es la reutilización de código entre componentes.
En el siguiente ejemplo se va a crear un Hook propio que encapsule la lógica de un contador.
import { useState } from "react";

export const useCounter = (initial: number) => { // (A)
  const [counter, setCounter] = useState(initial); // (B)

  const add = (value: number) => setCounter(counter + value); // (C)

  const next = () => add(1);

  const previous = () => add(-1);

  return { value: counter, next, previous }; // (D)
};
En (A) se declara el Hook. Los Hooks son funciones que pueden recibir parámetros.
En (B) se declara el estado interno del Hook con el valor inicial del parámetro.
En (C) se declara la función add que se ocupará de modificar el estado.
En (D) se devuelven las variables y funciones a las que queremos tener acceso desde el componente.

 

En este Hook, se devuelve un objeto con las propiedades value, next, previous.
No se está devolviendo la función add. No es necesario y en este caso no queremos dar el poder de cambiar el estado desde el componente directamente, sin pasar por next o previous.
Es recomendado que todos los Hooks empiecen por use.

 

En el siguiente ejemplo se utiliza el Hook que acabamos de crear useCounter .

import React from "react";
import { useCounter } from "../hooks/useCounter";

interface Props {
  initial: number;
}

export const ClickCounter: React.FC<Props> = props => {
  const { value, next, previous } = useCounter(props.initial); // (E)

  const onPrevious = () => {
    previous();
  };

  const onNext = () => {
    next();
  };

  return (
    <>
      <button onClick={onPrevious}>Previous</button>
      {value}
      <button onClick={onNext}>Next</button>
    </>
  );
};
En (E) declaramos que queremos usar nuestro Hook useCounter. Y tenemos acceso a las funciones que este devuelve.

useEffect

useEffect  nos permite ejecutar un efecto secundario cuando se modifica una prop o un estado de useState.
useEffect  sustituye a las funciones de ciclo de vida componentDidMount, componentDidUpdate, componentWillUnmount.
Línea temporal del funcionamiento del hook de useEffect
En el siguiente ejemplo se cambia el título del documento cuando el estado del contador cambia.
import React, { useEffect } from "react";
import { useCounter } from "../hooks/useCounter";

interface Props {
  initial: number;
}

export const ClickCounter: React.FC<Props> = props => {
  const { value, next, previous } = useCounter(props.initial);

  const onPrevious = () => {
    previous();
  };

  const onNext = () => {
    next();
  };

  useEffect(() => { // (A)
    document.title = value.toString(); // (B)
  }, [value]); // (C)

  return (
    <>
      <button onClick={onPrevious}>Previous</button>
      {value}
      <button onClick={onNext}>Next</button>
    </>
  );
};
En (A) , vemos que useEffect es una función que recibe dos parámetros.
El primero es el callback, que se va a ejecutar cuando alguna de las dependencias cambie. Aquí se cambia el título del documento (B).
En (C) declaramos las dependencias del efecto. Siempre que alguna de las dependencias cambie, el efecto se volverá a ejecutar.

State Binding

Sabiendo que los componentes funcionales se vuelven a ejecutar siempre que cambie una prop o estado, podemos servirnos de esto para cambiar el JSX fácilmente.
import React, { useEffect } from "react";
import { useCounter } from "../../hooks/useCounter";

interface Props {
  initial: number;
}

export const ClickCounter: React.FC<Props> = props => {
  const { value, next, previous } = useCounter(props.initial);

  const onPrevious = () => {
    previous();
  };

  const onNext = () => {
    next();
  };

  useEffect(() => {
    document.title = value.toString();
  }, [value]);

  // (A)
  const isMaxValue = value === 5;
  const isMinValue = value === -5;

  return (
    <>
      <button onClick={onPrevious} disabled={isMinValue}>
        Previous
      </button>
      {value}
      <button onClick={onNext} disabled={isMaxValue}>
        Next
      </button>
    </>
  );
};
En (A), estamos declarando dos variables que controlarán si los botones de previous  o next  están deshabilitados.

useContext

useContext es un Hook que nos permite acceder al contexto de un Provider.
Gráfica que muestra cómo funciona el hook useContext
En el siguiente ejemplo se implementa un contexto para guardar el tema de la aplicación.
import React, { useContext } from "react";

enum Themes {
  Dark = "Dark",
  Light = "Light"
}

const ThemeContext = React.createContext<Themes>(Themes.Dark); // (A)

export const ThemeProvider: React.FC = () => (
  <ThemeContext.Provider value={Themes.Dark}>
    <ButtonRow></ButtonRow>
  </ThemeContext.Provider>
);

const ButtonRow: React.FC = () => (
  <section>
    <Button></Button>
    <Button></Button>
    <Button></Button>
  </section>
);

const Button: React.FC = () => {
  const theme = useContext(ThemeContext); // (B)

  const className = "button " + theme;

  return <button className={className}></button>;
};
En (A)  se declara un contexto para almacenar el tema.
En (B)  se utiliza el Hook useContext  para obtener acceso al contexto superior.

Referencias

Para seguir con Hooks, aquí está la documentación oficial:

reactjs.org/docs/hooks-intro

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad