В предыдущей статье ‹link› вы узнали, как настроить свою первую среду React и запустить приложение с помощью CRA.

useState — это хук в React, который позволяет вам добавлять состояние к функциональным компонентам. Он возвращает пару значений: текущее состояние и функцию, которую можно использовать для обновления состояния. Вот пример того, как вы можете использовать useState для добавления части состояния с именем message к функциональному компоненту:

import React, { useState } from 'react';

function MyComponent() {
  const [message, setMessage] = useState('Hello World');

  return (
    <div>
      <p>{message}</p>
      <button onClick={() => setMessage('Hello from the button!')}>
        Update message
      </button>
    </div>
  );
}

В этом примере message — это текущее значение состояния, а setMessage — это функция, которую можно использовать для обновления значения message. В качестве начального состояния мы используем строку «Hello World», хотя начальное состояние не нужно определять, вместо этого вы можете использовать тип (строка, логическое значение, массив и т. д.). Итак, если мы собираемся установить тип для message, это будет просто useState('').

При нажатии кнопки вызывается функция setMessage с новым значением для message, которое обновляет состояние и вызывает повторную визуализацию компонента с новым значением.

Важно отметить, что useState следует вызывать внутри тела функционального компонента, а не в области видимости верхнего уровня или в любой другой части кода.

Предостережения useState

  • при использовании useState заключается в том, что обновление состояния может быть применено не сразу. Это может быть проблемой, если вы полагаетесь на обновленное значение состояния в той же функции или блоке кода, где вы вызываете функцию обновления состояния.
  • Например, рассмотрим следующий код:
const [count, setCount] = useState(0);

function increment() {
  setCount(count + 1);
  console.log(count);  // Logs 0, not 1
}

В этом примере функция increment увеличивает значение count на 1, но обновление состояния может быть применено не сразу. Это означает, что оператор console.log будет регистрировать старое значение count, а не обновленное значение.

Чтобы обойти эту проблему, вы можете использовать второй аргумент функции setState, который представляет собой обратный вызов, который будет выполняться после применения обновления состояния. Например:

function increment() {
  setCount(count + 1, () => {
    console.log(count);  // Logs the updated value of count
  });
}

Кроме того, вы можете использовать хук useEffect для выполнения действия после применения обновления состояния. Например:

useEffect(() => {
  console.log(count);  // Logs the updated value of count
}, [count]);
  • Состояние, возвращаемое useState, всегда является одним значением. Если вам нужно сохранить несколько значений в состоянии, вы можете использовать объект или массив для хранения значений и оператора расширения для их обновления. Например:
const [state, setState] = useState({ count: 0, message: 'Hello World' });

setState({ ...state, count: state.count + 1 })
console.log(state) // count: 1, message: 'Hello World'

Если бы вы собирались только обновить счетчик, не копируя предыдущее состояние, то состояние сообщения было бы удалено.

setState({ count: state.count + 1 })
console.log(state) // count: 1
  • useStateработает только с простыми значениями (числа, строки, логические значения и т. д.). Если вам нужно хранить более сложные значения в состоянии (например, объекты или массивы), вы должны быть осторожны, чтобы не изменять их напрямую, потому что это может привести к непредвиденному поведению. Вместо этого вы должны создать новую копию значения и обновить состояние новой копией. Например:
const [items, setItems] = useState([1, 2, 3]);

const newItems = [...items, 4];
setItems(newItems) 
console.log(items) // [1,2,3,4]

И без оператора распространения:

const [items, setItems] = useState([1, 2, 3]);

const newItems = [4];
setItems(newItems) 
console.log(items) // [4]
  • useStateследует использовать только для значений, которые изменяются внутри компонента. Если вам нужно сохранить значения, поступающие извне компонента (например, свойства или контекст), вы должны использовать хук useEffect для обновления состояния при изменении значений. Крюк useEffect будет рассмотрен в следующей статье!

Практическое задание

А теперь пришло время лучше запомнить собранную информацию, для этого я создал очень простое и короткое задание, которое поможет вам закрепить знания в области useState.

  1. В своем репозитории создайте функциональный компонент с именем Counter. Откройте файл src/App.js и импортируйте вновь созданный компонент и хук useState из пакета react.
  2. В компоненте Counter вызовите хук useState, вы можете вызвать значения count и setCount. Начальное значение счетчика должно быть 0.
  3. В JSX отобразите текущее значение count и добавьте обработчик onClick к кнопке, которая увеличивает значение count с помощью функции обновления, возвращаемой useState.
  4. Если это было слишком просто, добавьте еще два обработчика в свой Counter . Первый для уменьшения текущего значения countvalue, а второй для сброса значения счетчика в начальное состояние.

Вот как должен выглядеть компонент Counter (базовый):

import React, { useState } from 'react';

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

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

Бонус:

import React, { useState } from 'react';

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

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
      <button onClick={() => setCount(count - 1)}>
        Decrement
      </button>
      <button onClick={() => setCount(INIT_STATE)}>
        Reset
      </button>
      <p>Count: {count}</p>
    </div>
  );

Надеюсь, вам было легко понять, как работает useState. В следующей статье я расскажу о крючке useEffect.