Ganchos de reacción

# Ganchos de reacción

Los ganchos son una nueva adición en reaccionar 16.8. Le permiten usar el estado y otras características de React sin escribir un componente de clase.

Después de esta adición, el componente funcional ya no es un componente sin estado. Ahora, podemos lograr el comportamiento del componente usando la función de la forma en que solíamos tener con ganchos de ciclo de vida de componente de clase como ComponenteDidMount, ComponentWillUnmount, componenteDidUpdate etc.. Aquellos donde el componente importante de uso común y podemos lograr lo mismo con gancho useEffect.

A menudo hemos tenido que mantener componentes que comenzaron siendo simples pero que se convirtieron en un caos inmanejable de lógica con estado y efectos secundarios. Cada método de ciclo de vida a menudo contiene una combinación de lógica no relacionada. Por ejemplo, los componentes pueden realizar algunas búsquedas de datos en componentDidMount y componentDidUpdate. Sin embargo, el mismo método componentDidMount también puede contener alguna lógica no relacionada que configura detectores de eventos, con la limpieza realizada en componentWillUnmount. El código relacionado mutuamente que cambia en conjunto se divide, pero el código que no tiene ninguna relación termina combinado en un solo método. Esto hace que sea demasiado fácil introducir errores e inconsistencias.

En muchos casos, no es posible dividir estos componentes en otros más pequeños porque la lógica de estado está por todas partes. También es difícil probarlos. Esta es una de las razones por las que muchas personas prefieren combinar React con una biblioteca de administración de estado separada. Sin embargo, eso a menudo introduce demasiada abstracción, requiere que salte entre diferentes archivos y hace que la reutilización de componentes sea más difícil.

Para resolver esto, Hooks le permite dividir un componente en funciones más pequeñas en función de qué piezas están relacionadas (como configurar una suscripción o obtener datos), en lugar de forzar una división basada en métodos de ciclo de vida. También puede optar por administrar el estado local del componente con un reductor para hacerlo más predecible. A continuación hay listas de los ganchos que se agregaron:

Ganchos básicos

  • useState
  • efecto de uso
  • useContext

Ganchos adicionales

  • useCallback
  • usar nota
  • usarreductor
  • useRef
  • useImperativeManager
  • useLayoutEffect
  • usarDebugValue

useState

Devuelve un valor con estado y una función para actualizarlo. Si el nuevo estado se calcula utilizando el estado anterior, puede pasar una función a setState o un valor actualizado. En caso de función, recibirá el valor anterior y devolverá un valor actualizado. Aquí hay un ejemplo de un componente de contador que usa ambas formas de setState:

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
    </>
  );
}

Convirtamos el componente de clase en un componente funcional para enviar firstName y lastName en un formulario. A continuación se muestra el componente de clase UserForm.

import React, { Component } from "react";
class UserForm extends Component {
  constructor(props) {
    super(props);
    this.state = {
      firstName: "",
      lastName: ""
    };
    this.handleInputChange = this.handleInputChange.bind(this);
  }
  handleInputChange(event) {
    this.setState({
      [event.target.name]: event.target.value
    });
  }
  render() {
    const { firstName, lastName } = this.state;
    return (
      <form>
        <input
          value={firstName}
          onChange={this.handleInputChange}
          placeholder="First name"
          type="text"
          name="firstName"
          required
        />
        <input
          value={lastName}
          onChange={this.handleInputChange}
          placeholder="Last name"
          type="text"
          name="lastName"
          required
        />
        <button type="submit">Submit</button>
      </form>
    );
  }
}
export default UserForm;

El componente funcional equivalente para el componente de clase anterior se puede escribir de la siguiente manera:

import React, { useState } from "react";
import "./styles.css";
function UserForm() {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  return (
    <form>
      <input
        value={firstName}
        onChange={e => setFirstName(e.target.value)}
        placeholder="First name"
        type="text"
        name="firstName"
        required
      />
      <input
        value={lastName}
        onChange={e => setLastName(e.target.value)}
        placeholder="Last name"
        type="text"
        name="lastName"
        required
      />
      <button type="submit">Submit</button>
    </form>
  );
}
export default UserForm;

Básicamente estamos declarando una variable de estado y una función que nos permita modificar la variable de estado más adelante. La cadena vacía en la llamada useState es el valor inicial de firstName y se puede establecer en cualquier valor requerido. Lo estableceremos en una cadena vacía por ahora.
Tenga en cuenta que puede nombrar la función setFirstName como desee. Sin embargo, es una convención agregar ‘set’ antes del nombre de la variable de estado que estamos modificando.

efecto de uso

useEffect está destinado a manejar cualquier tipo de “efecto secundario” (realizar un cambio en algún sistema externo, iniciar sesión en la consola, realizar una solicitud HTTP, etc.) que se desencadena por un cambio en los datos de su componente o en reacción a la representación del componente. Reemplaza componenteDidMount, componenteDidUnmount y componenteDidReceiveProps, o algún código que se ejecuta cada vez que cambia su estado. Puede ser un desafío comprender los matices de su uso, pero al comprender cuándo se ejecuta y cómo controlarlo, puede ser un poco más fácil comprenderlo.

Ejecuta el efecto en cada render

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

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

  useEffect(() => {
    console.log(`The count is ${count}`);
  });

  return (
    <div>
      <p>Count is {count}</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}>
        increase
      </button>
    </div>
  );
}

Ejecuta el efecto solo una vez

Digamos que solo queríamos que el efecto se ejecutara una sola vez… piense en esto como un reemplazo para componentDidMount. Para ello, pase un [] como segundo argumento para useEffect:

import React, { useEffect } from "react";

default function Mounted() {
  useEffect(() => {
    console.log("mounted");
  }, []);

  return <div>This component has been mounted.</div>;
}

Ejecute el efecto cuando cambien los datos

Si lo que realmente desea es ejecutar el efecto solo cuando cambia un valor específico… por ejemplo, para actualizar algún almacenamiento local o activar una solicitud HTTP, querrá pasar esos valores que está observando en busca de cambios como el segundo argumento. Este ejemplo escribirá el nombre del usuario en el almacenamiento local cada vez que se actualice (activado por onChange de la entrada).

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

default function Listen() {
  const [name, setName] = useState("");

  useEffect(
    () => {
      localStorage.setItem("name", name);
    },
    [name]
  );

  return (
    <div>
      <input
        type="text"
        onChange={e => {
          setName(e.target.value);
        }}
        value={name}
      />
    </div>
  );
}

Limpiando de tu efecto

A veces es necesario deshacer lo que ha hecho… para limpiar después de usted mismo cuando se va a desmontar el componente. Para lograr esto, puede devolver una función de la función pasada a useEffect… eso es un bocado, pero veamos un ejemplo real, de lo que sería tanto el componenteDidMount como el componenteDidUnmount combinados en un solo efecto.

import React, { useEffect } from "react";

default function Listen() {
  useEffect(() => {
    const listener = () => {
      console.log("I have been resized");
    };
    window.addEventListener("resize", listener);

    return () => {
      window.removeEventListener("resize", listener);
    };
  }, []);

  return <div>resize me</div>;
}

Evite establecer el estado en componentes desmontados

Debido a que los efectos se ejecutan después de que el componente haya terminado de renderizarse, y debido a que a menudo contienen código asíncrono, es posible que para cuando se resuelva el código asíncrono, ¡el componente ya no esté montado! Cuando llegue el momento de llamar a la función setData para actualizar el estado, recibirá un error que indica que no puede actualizar el estado en un componente desmontado.

La forma en que podemos resolver el problema mencionado anteriormente (sin juego de palabras) es mediante el uso de una variable local y aprovechando la función de “limpieza” devuelta por nuestra función de efecto. Al comenzar como verdadero, podemos cambiarlo a falso cuando se limpia el efecto y usar esta variable para determinar si todavía queremos llamar a la función setData o no.

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

default function Fetcher({ url }) {
  const [data, setData] = useState(null);

  useEffect(
    () => {
      // Start it off by assuming the component is still mounted
      let mounted = true;

      const loadData = async () => {
        const response = await Axios.get(url);
        // We have a response, but let's first check if component is still mounted
        if (mounted) {
          setData(response.data);
        }
      };
      loadData();

      return () => {
        // When cleanup is called, toggle the mounted variable to false
        mounted = false;
      };
    },
    [url]
  );

  if (!data) {
    return <div>Loading data from {url}</div>;
  }

return <div>{JSON.stringify(data)}</div>;
}

useContext

useContext hace que Context sea un poco más fácil de consumir. La forma típica de usar la API de contexto se ve así:

import React from "react";
import ReactDOM from "react-dom";

// Create a Context
const NumberContext = React.createContext();
// It returns an object with 2 values:
// { Provider, Consumer }

function App() {
  // Use the Provider to make a value available to all
  // children and grandchildren
  return (
    <NumberContext.Provider value={42}>
      <div>
        <Display />
      </div>
    </NumberContext.Provider>
  );
}

function Display() {
  // Use the Consumer to grab the value from context
  // Notice this component didn't get any props!
  return (
    <NumberContext.Consumer>
      {value => <div>The answer is {value}.</div>}
    </NumberContext.Consumer>
  );
}

ReactDOM.render(<App />, document.querySelector("#root"));

¿Ves cómo obtenemos el valor dentro del componente Display? Tenemos que envolver nuestro contenido en un NumberContext.Consumer y usar el patrón de accesorios de representación (pasar una función como elemento secundario) para recuperar el valor y mostrarlo.

Esto funciona bien, y los “accesorios de representación” son un gran patrón para pasar datos dinámicos, pero introducen algunos anidamientos innecesarios y cierta sobrecarga cognitiva (especialmente si no está acostumbrado).

Reescribamos la pantalla usando el nuevo enlace useContext y veamos cómo se ve:

// import useContext (or we could write React.useContext)
import React, { useContext } from 'react';

// ...

function Display() {
  const value = useContext(NumberContext);
  return <div>The answer is {value}.</div>;
}

useCallback vs useMemo

Las API de useCallback y useMemo tienen un aspecto similar. Ambos toman una función y una matriz de dependencias.

useCallback(fn, deps);
useMemo(fn, deps);

Entonces cuál es la diferencia? useCallback devuelve su función sin llamar para que pueda llamarla más tarde, mientras que useMemo llama a su función y devuelve el resultado.

Quiere usar useCallback o useMemo siempre que dependa de igualdad referencial entre renders. En React, las funciones definidas en los componentes de función se vuelven a crear en cada renderizado debido al cierre. Y, por lo tanto, si está utilizando la función como dependencia en useEffect, esto conducirá a un bucle infinito. Entonces, para evitar esto, deberíamos usar useCallback. A continuación se muestra una excelente publicación que explica el significado de la igualdad referencial y destaca la diferencia entre usecallback-vs-usememo.

Similar Posts

Leave a Reply

Your email address will not be published.