Introducción a React Hooks

April 6, 2019 • ☕️ 4 minutos de lectura

Introducción

⚠️ React se incorpora en la versión 16.8 y es retrocompatible, esto quiere decir que podremos seguir usando las class, aunque deberíamos ir migrando poco a poco nuestro código.

¿Qué son los hooks?

Los react hooks son funciones que nos permiten conectarnos (engancharnos) al estado de react y a las características del ciclo de vida de los componentes. Esto quiere decir que podemos crear componentes funcionales con estado, sin necesidad de crear una class.

¿Porqué molan los hooks?… pues por muchas razones, entre ellas…

  1. Escribo menos código
  2. El código de nuestro bundle pesará menos y estará más optimizado, aquí os dejo un enlace para que podáis verlo con vuestros propios ojos Babeljs.io.
  3. Nos olvidamos de llamar a this.

Hooks de estado

Nos permiten manipular el estado de un componente de React.

Se crea una constant con un array con dos valores [nombre, setNombre] y luego asignarle un estado inicial con useState.

const [contador, setContador] = useState(0)

Para actualizar el estado lo haremos con setNombre

<button onClick={() => setNombre(nuevoValor)}>Botón</button>

Hook de efecto

Nos permite realizar “efectos secundarios” en nuestros componentes funcionales.

Si estás familiarizado con el ciclo de vida de las clases de React y sus métodos, el Hook useEffect equivale a componentDidMount, componentDidUpdate y componentWillUnmount combinados en useEffect.

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar a componentDidMount y componentDidUpdate:
  useEffect(() => {
    // Actualiza el título del documento usando la Browser API
    document.title = `has hecho click ${count} times`;
  });

  return (
    <div>
      <p>Has hecho click {count} veces</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

También podemos controlar cuando se ejecuta el componente, ya que si no, por defecto se seguirá ejecutando cada vez actualicemos el estado.

Para ello solo tenemos que pasarle un array vacio y este solo se ejecutará una vez el componente se ha montado.

import React, { useEffect } from "react"

export default function MyApp() {
  useEffect(()=> {
    console.log("Se ha cargado el componente...")
  }, [])
}

Pero si queremos que cada vez que hagamos un cambio se actualice, deberemos pasarle en el array el valor.

import React, { useState, useEffect } from "react"

export default function MyApp() {
  const [nombre, setNombre] = useState('')

  useEffect(()=> {
    console.log(`El nuevo nombre es ${nombre}`)
    localStorage.setItem("nombre", nombre)
  })

  return (
    <div>
      <input onChange={ e => {
        setNombre(e.target.value)
      }}
      value={nombre}
      />
    </div>
  )
}

Ejemplos

Hooks de estado

Este primer código, no es un hook, es una clase normal y corriente de React, pero nos servirá para entender mejor el ejemplo.

import React, { Component } from "react"
export default class MyApp extends Component {
  state = {
    contador: 0,
  }
  render() {
    return (
      <div>
        Contador: {this.state.contador}
        <button
          onClick={() => this.setState({ contador: this.state.contador + 1 })}
        >
          Aumentar
        </button>
      </div>
    )
  }
}

Este será nuestro primer hook, hace lo mismo que el código anterior pero usando el hook useState, es similar a this.setState en una clase.

import React, { useState } from "react"
export default function MyApp() {
  const [contador, setContador] = useState(0)
  return (
    <div>
      Contador: {contador}
      <button onClick={() => setContador(contador + 1)}>Aumentar</button>
    </div>
  )
}

Usar un hook para almacenar varios estados

Aquí usaremos useState para almacenar varios estados, además usaremos el hook useEffect para controlar el ciclo de vida.

import React, { useEffect, useState } from "react"

function useCoordenadas() {
  const [coordenadas, setCoordenadas] = useState({
    latitud: null,
    longitud: null,
  })
  let geoId

  useEffect(() => {
    // componentDidMount
    geoId = window.navigator.geolocation.watchPosition(position => {
      setCoordenadas({
        latitud: position.coords.latitude,
        longitud: position.coords.longitude,
      })
    })
    // componentWillUnmount
    return () => {
      navigator.geolocation.clearWatch(geoId)
    }
  })
  return coordenadas
}

export default function coordenadas() {
  const coordenadas = useCoordenadas()

  return coordenadas.latitud == null ? (
    <div>Cargando...</div>
  ) : (
    <div>
      <h2>Latitud: {coordenadas.latitud}</h2>
      <h2>Longitud: {coordenadas.longitud}</h2>
    </div>
  )
}

Fetch a una api usando hooks

El efecto del hook se ejecuta cuando el componente se monta, pero también cuando el componente se actualiza. Debido a que estamos configurando el estado después de cada captura de datos, el componente se actualiza y el efecto se ejecuta nuevamente. Obtiene los datos una y otra vez. Para evitar este error y obtener los datos una vez se monta el componente, pasaremos como segundo argumento del hook useEffect un array vacio y así evitar activarlo en las actualizaciones del componente.

import React, { useState, useEffect } from "react"
import axios from "axios"

function MyApp() {
  const [data, setData] = useState({ data: [] })

  useEffect(() => {
    const getPhotos = async () => {
      const result = await axios("https://jsonplaceholder.typicode.com/photos")
      setData(result)
    }
    getPhotos()
  }, [])

  return (
    <ul>
      {data.data.map(item => (
        <li key={item.id}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  )
}

export default MyApp