DEV Community

cdenis
cdenis

Posted on

React hooks: useState

Índice:

Descripción

useState nos permite agregarle un estado a un componente funcional.

Retorna un par de valores:

  • el estado.
  • una función para poder actualizarlo.
  const [count, setCount] = useState(0);
Enter fullscreen mode Exit fullscreen mode

En nuestro ejemplo anterior, count es nuestro estado y está inicializado con el valor 0 y setCount es nuestra función para poder actualizarlo.

Dato:
Observemos que estamos haciendo una destructuración de un array cuando ejecutamos el hook useState, lo que nos da la posibilidad de poder llamar a nuestro estado y función para actualizarlo como querramos. Por convención la función debe comenzar con set.

useState espera un solo argumento, el cual sería el valor por defecto que tendría nuestro estado. A diferencia del estado en los componentes de clases, nuestro estado pueden ser strings, numbers, etc.

  import { useState } from 'react';

  const [count, setCount] = useState(0);
  const [text, setText] = useState('Hi there!');
  const [user, setUser] = useState({
    name: 'Denis',
    job: 'Frontend Enginner'
  });
  const [shoppingList, setShoppingList] = useState([
    {
      item: 'laptop',
      price: 900,
      currency: ''
    }
  ]);
Enter fullscreen mode Exit fullscreen mode

Volver al índice


Diferencia con this.setState

Tenemos que tener en cuenta a la hora de actualizar nuestro estado que a diferencia del this.setState de los componentes de clase donde el estado es siempre un objeto y podemos actualizar una propiedad del mismo directamente sin afectar al resto, que nuestra función devuelta por el hook useState va a reemplazar por completo nuestro estado por el valor que nosotros le pasemos, por ende, si nuestro estado por ej, es un objeto y nosotros quisiéramos actualizar una sola propiedad, deberíamos pasarle la propiedad actualizada y además, el resto de sus propiedades.

Class component

  // ...
  constructor(props) {
    super(props);
    // Definimos nuestro estado
    this.state = {
      count: 0,
      text: "class text"
    };
    this.onClick = this.onClick.bind(this);
  }

  onClick() {
    // Destructurando obtenemos el valor de count
    const { count } = this.state;
    // Actualizamos el valor de count sin afectar
    // el valor de text
    this.setState({ count: count + 1 });
  }
  // ...
Enter fullscreen mode Exit fullscreen mode

Functional component

  // ...
  // Destructurando obtenemos los valores de count y text
  const [{ count, text }, setState] = React.useState({
    count: 0,
    text: "functional text"
  });

  const onClick = () => {
    // Actualizamos el valor de count y mantenemos el de text
    setState({
      count: count + 1,
      text
    });

    // También podríamos actualizar nuestro estado haciendo
    // uso de una función. (Recomendado)
    setState(prevState => ({
      ...prevState,
      count: count + 1
    }));
  }
  // ...
Enter fullscreen mode Exit fullscreen mode

Dato:
Si a setState solo le pasariamos el valor de count, perderíamos todo rastro de text, dejaría de existir.

Ejemplo en CodeSandbox

Volver al índice


Lazy initial state

Si el valor por defecto que queremos asignarle a nuestro estado es el resultado de un calculo costoso, podemos utilizar el lazy initial state, es decir, es vez de pasarle nuestro estado inicial, lo que hacemos es pasarle una función que lo calcule, esto se ejecutará una sola vez en el render inicial.

function getExpensiveState() {
  // Calculo costoso
}

// Nuestro componente va a realizar el calculo costoso
// en cada render aunque no utilice su valor más allá del
// primer render.
function ComponentWithoutLazy() {
  const [state, setState] = React.useState(getExpensiveState());

  // ...
}

// Ahora nuestro componente solo va a realizar el calculo
// costoso en el primer render.
function ComponentWithLazy() {
  const [state, setState] = React.useState(() => getExpensiveState());

  // ...
}
Enter fullscreen mode Exit fullscreen mode

Ejemplo en CodeSandbox

Volver al índice


Functional updates

Cuando nuestro componente es simple y no contiene muchas actualizaciones de estado ejecutadas por diversos eventos, cambios de props, etc, no vamos a tener problemas actualizando nuestro estado seteando el nuevo directamente.

function Counter() {
  const [count, setCounter] = React.useState(0);

  function onClick() {
    setCounter(count + 1);
  }

  // Code
}
Enter fullscreen mode Exit fullscreen mode

Pero cuando nuestro componente comienza a manejar más lógica y este estado es actualizado en distintas oportunidades por distintos eventos, acciones, etc. Lo mejor y más recomendable, es utilizar una función para actualizar nuestro estado con setState, de esta manera:

function Counter() {
  const [count, setState] = React.useState(0);

  function onClick() {
    setState(prevState => ({
      ...prevState,
      count: prevState + 1
    }));
  }

  // Code
}
Enter fullscreen mode Exit fullscreen mode

Por qué? Porque utilizando una función nos aseguramos de tener el último valor de nuestro estado para poder actualizarlo en consecuencia y evitar inconsistencias o valores erróneos.

Ejemplo en CodeSandbox

Volver al índice

Top comments (1)

Collapse
 
scriptkavi profile image
ScriptKavi

Many early birds have already started using this custom hooks library
in their ReactJs/NextJs project.

Have you started using it?

scriptkavi/hooks

PS: Don't be a late bloomer :P