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.
- Componentes simples sin estado.
- Estilos reutilizables.
useState

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> </> ); };
- 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.
Creando un Hook propio
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 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> </> ); };
useEffect

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> </> ); };
State Binding
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> </> ); };
useContext

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>; };