Использование состояния в ваших компонентах функции React

Что такое крючок?

React Hooks - это функции, которые позволяют нам работать с функциями состояния и жизненного цикла в компонентах функций React. Раньше это было возможно только при использовании классов, но хуки дают нам альтернативный способ использования этих важных функций класса вне классов.

Что такое useState?

Перехватчик состояния (useState) - это наиболее часто используемый перехватчик для создания компонентов React - он позволяет нам добавлять состояние к нашим функциональным компонентам без необходимости преобразовывать их в классы.

Использование состояния в обычном компоненте класса React:

class MyClass extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'Medium'
    };
  }

Использование состояния в компоненте функции React:

import React, { useState } from 'react';
function MyFunction() {
  const [name, setName] = useState('Medium');
}

Мы импортируем useState из библиотеки React, как показано выше. Функция useState () возвращает массив, содержащий два значения:

  • Текущее состояние = текущее значение нашего состояния (в нашем примере мы назначаем это константному имени)
  • State Setter = функция, используемая для обновления нашего состояния (обычно присваивается константе с тем же именем, что и текущее состояние, с префиксом «set» с верблюжьей оболочкой, например, setName)

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

Состояние инициализации

При назначении нашего текущего состояния мы можем столкнуться с проблемами, если наше начальное состояние не инициализировано. Если мы попытаемся получить доступ к нашему состоянию после первоначального рендеринга, но перед повторным рендерингом, мы обнаружим, что наше состояние «undefined».

Неинициализировано:

const [name, setName] = useState();

Вышеупомянутое присвоение не инициализирует состояние нашего имени, и если оно будет вызвано перед использованием нашей функции установки состояния, оно просто вернет «undefined». Чтобы бороться с этим, мы инициализируем наше состояние как аргумент в вызове функции useState ().

Инициализировано:

const [name, setName] = useState('Medium');

Теперь, вызывая наше состояние имени после первоначального рендеринга, мы получим начальное состояние «Среднее» в качестве нашего имени. Теперь, когда мы меняем состояние, наше новое значение просто переопределяет предыдущее начальное состояние.

Примечание: это не обязательно должна быть строка, это может быть любое начальное состояние, которое вам нравится (например, число, логическое значение, объект, массив и т. д.). Его можно даже инициализировать как пустые строки, объекты и т. д.)

Использование состояния

В случае с компонентами класса для доступа к нашему состоянию необходимо вызвать this.state:

<h1>Hello, {this.state.name}.</h1>

С функциональными компонентами нам больше не нужно беспокоиться об использовании this.state и мы можем напрямую отображать наше состояние следующим образом:

<h1>Hello, {name}.</h1>

Возврат: Здравствуйте, средний.

Это делает наш код намного чище и избавляет нас от неизбежной отладки, когда мы забываем об этом. Это также избавляет нас от необходимости связывать this с любыми функциями, как мы это делаем с компонентами класса.

Обновление состояния

Чтобы обновить наше состояние, мы используем нашу функцию установки состояния (set ___ ()), определенную ранее. В нашем примере это setName:

setName('New Medium');

Это изменяет наше текущее состояние имени на «New Medium» и повторно выполняет рендеринг нашего функционального компонента.

<h1>Hello, {name}.</h1>

Теперь возвращается: Здравствуйте, новый канал.

Обновление из предыдущего состояния

Пример 1. Число

Часто мы хотим, чтобы наше состояние оставалось неизменным, и просто добавляли в него дополнительные данные. Допустим, у нас есть счетчик, который мы хотим увеличивать при нажатии кнопки. В этом случае нам нужно обновить наше состояние с помощью функции обратного вызова. Без функции обратного вызова мы рискуем использовать «устаревшие» значения состояния.

function Counter() {
   const [count, setCount] = useState(0);
   const increment = () => setCount(prevCount => prevCount + 1);
   
   return (
     <div>
       <p>Clicks: {count}</p>
       <button onClick={increment}>Increment</button>
     </div>   );
}

В этом примере у нас есть компонент функции счетчика с функцией приращения (обработчик событий), которая вызывает setCount () с помощью функции обратного вызова. Мы передаем prevCount в качестве аргумента, который возвращает prevCount + 1 в качестве нашего обновленного состояния. Мы также можем увидеть, как мы можем использовать обработчики событий в нашем JSX, которые будут вызываться при выполнении таких действий, как нажатие кнопки (см. Атрибут кнопки onClick).

Пример 2: Массив

Теперь предположим, что у нас есть имя, которое мы хотели бы добавить к массиву имен.

function Names() {
  const [names, setNames] = useState(['Medium', 'Jeff']);
  
  const addName = (name) {
    setNames((prev) => {
      return [name, ...prev];
    });
  };

Здесь у нас есть обработчик событий addName, который принимает имя в качестве аргумента и добавляет его в начало в нашем массиве состояний с помощью setNames. «… Prev» используется для сохранения предыдущего массива состояний, добавляя новое имя в начало (если мы хотим добавить новое имя в конец, мы могли бы иметь [… prev, name]).

Если мы хотим удалить элемент из массива, мы можем использовать метод filter ():

  const removeItem = (targetIndex) => {
    setNames((prev) => {
      return prev.filter((item, index) => index !== targetIndex);
    });
};

Здесь мы передаем индекс значения, которое хотим удалить (targetIndex), и устанавливаем наше новое состояние как каждый элемент в предыдущем массиве - за исключением элемента с индексом, который мы хотели бы удалить.

Пример 3: объект

Наконец, допустим, у нас есть объект, содержащий множество деталей о человеке.

function Person() {
  const [details, setDetails] = useState({name: 'Medium'});
    const handleChange = ({ target }) => {
      const {name, value} = target;
      setDetails((prev) => ({
        ...prev,
        [name]: value
      }));
};

В этом примере мы передаем пару {name: value} в нашу функцию setDetails, которая также использует ... prev для изменения состояния на предыдущий объект с новой парой значений, добавленной к объекту.

Использование отдельных крючков

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

function Movie() {
  const [title, setTitle] = useState('Interstellar');
  const [actors, setActors] = useState(['Matthew McConaughey', 'Anne Hathaway']);
  const [ratings, setRatings] = useState({
    RottenTomatoes: '72%',
    IMDb: '86%',
    Metacritic: '74%'});
};

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

Вот и все, теперь вы можете использовать состояние в своих компонентах функции React! Просто помните, что это доступно только при использовании React и не может использоваться в компонентах класса. 😁