Простое и понятное руководство React useState() Hook (рекомендуемая коллекция длинной статьи)

JavaScript React.js

Автор: Дмитрий Павлютин

Переводчик: Front-end Xiaozhi

Источник: dmitripavlutin.com

Чем больше вы знаете, тем больше вы не знаете

Ставьте лайк и смотрите снова, формируйте привычку


эта статьяГитхаб:GitHub.com/QQ449245884…Он был включен в вышеизложенное, и более ранние статьи с высокими похвалами были классифицированы, а также было систематизировано множество моих документов и учебных материалов. Добро пожаловать в Star and Perfect. Вы можете обратиться в тестовый центр для ознакомления во время собеседования. Надеюсь, у нас что-то получится вместе.

Состояние — это информация, скрытая в компоненте, и компонент может изменить свое состояние без ведома родителя. Я предпочитаю функциональные компоненты, потому что они достаточно просты, чтобы можно было управлять состоянием функциональных компонентов.useState()Крюк.

В этой статье шаг за шагом объясняется, как использоватьuseState()Крюк. Кроме того, некоторые общиеuseState()яма.

1. ИспользуйтеuseState()Заниматься управлением состоянием

Функциональный компонент без состояния не имеет состояния и выглядит так (частичный код):

import React from 'react';

function Bulbs() {
  return <div className="bulb-off" />;
}

можно найтиcodesandboxпопытайся.

текущий результат:

На данный момент, как добавить кнопку для включения/выключения лампочки? Для этого нам нужны функциональные компоненты с состоянием, которые являются функциональными компонентами с состоянием.

useState()это хук, который реализует состояние выключателя лампочки, добавление состояния в функциональный компонент требует4Шаги: включить состояние, инициализировать, прочитать и обновить.

1.1 Активное состояние

к<Bulbs>Преобразование в компонент с состоянием требует сообщить React: from'react'импортировать в упаковкеuseStateловушка, которая затем вызывается в верхней части функции компонентаuseState().

Примерно так:

import React, { useState } from 'react';

function Bulbs() {
  ... = useState(...);
  return <div className="bulb-off" />;
}

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

Как только состояние включено, следующим шагом будет его инициализация.

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

В начале лампочка выключена, следует использовать соответствующее состояниеfalseИнициализировать хук:

import React, { useState } from 'react';

function Bulbs() {
  ... = useState(false);
  return <div className="bulb-off" />;
}

useState(false)использоватьfalseИнициализировать состояние.

После включения и инициализации состояния, как его прочитать?useState(false)что вернуть.

1.3 Статус чтения

когда крючокuseState(initialState)При вызове он возвращает массив, первый элемент которого является значением состояния.

const stateArray = useState(false);
stateArray[0]; // => 状态值

Читаем состояние компонента

function Bulbs() {
  const stateArray = useState(false);
  return <div className={stateArray[0] ? 'bulb-on' : 'bulb-off'} />;
}

<Bulbs>Состояние компонента инициализируетсяfalse, можно открытьcodesandboxПроверьте эффект.

useState(false)Возвращает массив с первым элементом, содержащим значение состояния, которое в данный моментfalse(потому что состояние используетсяfalseинициализация).

Мы можем использовать деструктуризацию массива для извлечения значений состояния в переменныеonначальство:

import React, { useState } from 'react';

function Bulbs() {
  const [on] = useState(false);
  return <div className={on ? 'bulb-on' : 'bulb-off'} />;
}

onПеременные состояния содержат значения состояния.

Статус включен и инициализирован, и теперь он доступен. Но как обновить? Давайте посмотримuseState(initialState)что вернуть.

####1.4 Статус обновления

обновить состояние со значением

Мы уже знаем,useState(initialState)Возвращает массив, где первый элемент является значением состояния, а второй элемент — функцией, которая обновляет состояние.

const [state, setState] = useState(initialState);

// 将状态更改为 'newState' 并触发重新渲染
setState(newState);

// 重新渲染`state`后的值为`newState`

Чтобы обновить состояние компонента, вызовите функцию обновления с новым состояниемsetState(newState). После повторного рендеринга компонента состояние получает новое значениеnewState.

при нажатии开灯Обновить состояние переключателя лампочки при нажатии кнопкиtrue, нажмите关灯обновлено доfalse.

import React, { useState } from 'react';

function Bulbs() {
  const [on, setOn] = useState(false);

  const lightOn = () => setOn(true);
  const lightOff = () => setOn(false);

  return (
    <>
      <div className={on ? 'bulb-on' : 'bulb-off'} />
      <button onClick={lightOn}>开灯</button>
      <button onClick={lightOff}>关灯</button>
    </>
  );
}

ОткрытьcodesandboxПопробуй сам.

При нажатии на световую кнопкуlightOn()функция будетonобновить доtrue: setOn(true). То же самое происходит, когда вы нажимаете выключить свет, только статус обновляется доfalse.

React будет повторно отображать компонент, как только его состояние изменится.onПеременная получает новое значение состояния.

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

Обновление состояния с помощью обратных вызовов

Когда новое состояние вычисляется с использованием предыдущего состояния, состояние можно обновить с помощью обратного вызова:

const [state, setState] = useState(initialState);
...
setState(prevState => nextState);

...

Вот некоторые примеры:

// Toggle a boolean
const [toggled, setToggled] = useState(false);
setToggled(toggled => !toggled);

// Increase a counter
const [count, setCount] = useState(0);
setCount(count => count + 1);

// Add an item to array
const [items, setItems] = useState([]);
setItems(items => [...items, 'New Item']);

Затем повторно реализуйте приведенный выше пример лампы следующим образом:

import React, { useState } from 'react';

function Bulbs() {
  const [on, setOn] = useState(false);

  const lightSwitch = () => setOn(on => !on);

  return (
    <>
      <div className={on ? 'bulb-on' : 'bulb-off'} />
      <button onClick={lightSwitch}>开灯/关灯</button>
    </>
  );
}

ОткрытьcodesandboxПопробуй сам.

setOn(on => !on)Используйте функцию для обновления состояния.

1.5 Краткое резюме

  • передачаuseState()Хук, чтобы включить состояние в функциональных компонентах.

  • useState(initialValue)первый параметрinitialValueявляется начальным значением состояния.

  • [state, setState] = useState(initialValue)возвращает содержащий2Массив элементов: значения состояния и функции обновления состояния.

  • вызвать функцию обновления состояния с новым значениемsetState(newState)обновить состояние. В качестве альтернативы можно использовать обратный вызовsetState(prev => next)для вызова средства обновления состояния, которое вернет новое состояние на основе предыдущего состояния.

  • После вызова средства обновления состояния React обеспечивает повторную визуализацию компонента, чтобы новое состояние стало текущим.

2. Несколько состояний

позвонив несколько разuseState(), функциональный компонент может иметь несколько состояний.

function MyComponent() {
  const [state1, setState1] = useState(initial1);
  const [state2, setState2] = useState(initial2);
  const [state3, setState3] = useState(initial3);
  // ...
}

Обратите внимание, убедитесь, чтоuseState()Множественные вызовы всегда находятся в одном и том же порядке между рендерами (подробнее об этом позже).

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

новое состояниеcountСодержит количество лампочек, начальное значение равно1:

import React, { useState } from 'react';

function Bulbs() {
  const [on, setOn] = useState(false);
  const [count, setCount] = useState(1);

  const lightSwitch = () => setOn(on => !on);
  const addBulbs = () => setCount(count => count + 1);

  const bulb = <div className={on ? 'bulb-on' : 'bulb-off'} />;
  const bulbs = Array(count).fill(bulb);

  return (
    <>
      <div className="bulbs">{bulbs}</div>
      <button onClick={lightSwitch}>开/关</button>
      <button onClick={addBulbs}>添加灯泡</button>
    </>
  );
}

Открыть демо, затем нажмите кнопку «Добавить лампочку»: количество лампочек увеличивается, нажмите кнопку включения/выключения, чтобы включить/выключить лампочку.

  • [on, setOn] = useState(false) управлять включенным/выключенным состоянием
  • [count, setCount] = useState(1)Управляйте количеством лампочек.

Несколько состояний могут корректно работать в одном компоненте.

3. Ленивое состояние инициализации

Всякий раз, когда React повторно отображает компонент, он будет выполненuseState(initialState). Если начальное состояние представляет собой примитивное значение (число, логическое значение и т. д.), проблем с производительностью не будет.

Когда начальное состояние требует дорогостоящих операций с производительностью, его можноuseState(computeInitialState)Предоставьте функцию для использования ленивой инициализации состояния следующим образом:

function MyComponent({ bigJsonData }) {
  const [value, setValue] = useState(function getInitialState() {
    const object = JSON.parse(bigJsonData); // expensive operation
    return object.initialValue;
  });

  // ...
}

getInitialState()Выполняется только один раз при начальном рендеринге для получения начального состояния. В будущих рендерах компонента он больше не будет вызываться.getInitialState()тем самым пропускаю дорогие операции.

4. Яма в тельце ()

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

4.1 Куда звонитьuseState()

В использованииuseState()При хуке вы должны следовать правилам хука

  1. Только вызовы Hook верхнего уровня: нельзя вызывать в циклах, условных выражениях, вложенных функциях и т. д.useState(). в несколькихuseState()В вызовах порядок вызовов должен быть одинаковым между рендерами.

  2. Хуки вызываются только из функций React: должны вызываться только внутри функциональных компонентов или пользовательских хуков.useState().

приди и посмотриuseState()Примеры правильного и неправильного употребления.

действительный вызовuseState()

useState()правильно вызывается на верхнем уровне функционального компонента

function Bulbs() {
  // Good
  const [on, setOn] = useState(false);
  // ...
}

Вызовите несколько правильно в том же порядкеuseState()передача:

function Bulbs() {
  // Good
  const [on, setOn] = useState(false);
  const [count, setCount] = useState(1);
  // ...

useState()правильно вызывается на верхнем уровне пользовательского хука

function toggleHook(initial) {
  // Good
  const [on, setOn] = useState(initial);
  return [on, () => setOn(!on)];
}

function Bulbs() {
  const [on, toggle] = toggleHook(false);
  // ...
}

useState()неверный вызов

Вызов в состоянииuseState()это неверно:

function Switch({ isSwitchEnabled }) {
  if (isSwitchEnabled) {
    // Bad
    const [on, setOn] = useState(false);
  }
  // ...
}

вызов вложенной функцииuseState()также неправильно

function Switch() {
  let on = false;
  let setOn = () => {};

  function enableSwitch() {
    // Bad
    [on, setOn] = useState(false);
  }

  return (
    <button onClick={enableSwitch}>
      Enable light switch state
    </button>
  );
}

4.2 Устаревшее состояние

Закрытие — это функция, которая захватывает переменные из внешней области.

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

来看看一个过时的状态是如何表现出来的。 сборка<DelayedCount>Задерживать3Секунды для подсчета количества нажатий кнопок.

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

  const handleClickAsync = () => {
    setTimeout(function delay() {
      setCount(count + 1);
    }, 3000);
  }

  return (
    <div>
      {count}
      <button onClick={handleClickAsync}>Increase async</button>
    </div>
  );
}

Открыть демо, быстро нажмите кнопку несколько раз.countПеременная неправильно записывает фактическое количество кликов, и некоторые клики съедаются.

delay()является устаревшим замыканием, которое визуализируется из исходного рендеринга (с использованием0устаревший пойман в инициализации)countПеременная.

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

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

  const handleClickAsync = () => {
    setTimeout(function delay() {
      setCount(count => count + 1);
    }, 3000);
  }

  return (
    <div>
      {count}
      <button onClick={handleClickAsync}>Increase async</button>
    </div>
  );
}

СейчасetCount(count => count + 1)существуетdelay()Правильно обновлять статус счетчика в . React гарантирует, что последнее значение состояния предоставляется в качестве аргумента функции обновления состояния, и проблема устаревших замыканий решена.

Открыть демоКраткий клик кнопки. После последней задержки,countправильно представляет количество кликов.

4.3 Комплексное управление состоянием

useState()Используется для управления простым состоянием. Для комплексного управления состоянием вы можете использоватьuseReducer()крюк. Он обеспечивает лучшую поддержку состояний, требующих операций с несколькими состояниями.

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

import React, { useState } from 'react';

function FavoriteMovies() {
  const [movies, setMovies] = useState([{ name: 'Heat' }]);

  const add = movie => setMovies([...movies, movie]);

  const remove = index => {
    setMovies([
      ...movies.slice(0, index),
      ...movies.slice(index + 1)
    ]);
  }

  return (
    // Use add(movie) and remove(index)...
  );
}

Попробуйте демоДобавьте и удалите свои любимые фильмы.

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

Лучшим решением является абстрагирование сложного управления состоянием вreducerсередина:

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'add':
      return [...state, action.item];
    case 'remove':
      return [
        ...state.slice(0, action.index),
        ...state.slice(action.index + 1)
      ];
    default:
      throw new Error();
  }
}

function FavoriteMovies() {
  const [state, dispatch] = useReducer(reducer, [{ name: 'Heat' }]);

  return (
    // Use dispatch({ type: 'add', item: movie })
    // and dispatch({ type: 'remove', index })...
  );
}

reducerДля управления состоянием фильма существует два типа операций:

  • "add"Вставить новый фильм в список

  • "remove"Удалить фильмы по индексу из списка

Попробуйте демоИ обратите внимание, что функционал компонента не изменился. Но эта версия<FavoriteMovies>Легче понять, потому что управление состоянием было извлечено вreducerсередина.

Еще одно преимущество: вы можетеreducerИзвлеките в отдельный модуль и повторно используйте его в других компонентах. Кроме того, даже без компонентов можноreducerДелайте модульные тесты.

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

4.4 Статус и ссылка

Рассмотрим сценарий, в котором мы хотим подсчитать, сколько раз компонент отрисовывается.

Простой способ сделать это - инициализироватьcountRenderсостояние и обновлять его при каждом рендеринге (используяuseEffect() hook)

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

function CountMyRenders() {
  const [countRender, setCountRender] = useState(0);
  
  useEffect(function afterRender() {
    setCountRender(countRender => countRender + 1);
  });

  return (
    <div>I've rendered {countRender} times</div>
  );
}

useEffect()вызывается после каждого рендераafterRender()Перезвоните. Но однаждыcountRenderКогда состояние обновится, компонент будет повторно визуализирован. Это вызовет еще одно обновление состояния, еще один повторный рендеринг и так далее.

изменяемая ссылкаuseRef()Сохраняйте изменяемые данные, которые не вызывают повторную визуализацию при их изменении, преобразуйте их с помощью изменяемых ссылок.<CountMyRenders>:

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

function CountMyRenders() {
  const countRenderRef = useRef(1);
  
  useEffect(function afterRender() {
    countRenderRef.current++;
  });

  return (
    <div>I've rendered {countRenderRef.current} times</div>
  );
}

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

Каждый раз, когда компонент визуализируется,countRenderRefПеременные ссылки сделаютcountRenderRef.current ++Увеличение. Важно отметить, что изменения не вызывают повторную визуализацию компонента.

5. Резюме

Чтобы сделать функциональный компонент с состоянием, вызовите тело функции компонентаuseState().

useState(initialState)Первый параметр — это начальное состояние. Возвращаемый массив имеет два элемента: текущее состояние и функцию обновления состояния.

const [state, setState] = useState(initialState);

использоватьsetState(newState)для обновления значения состояния. Кроме того, если вам нужно обновить состояние на основе предыдущего состояния, вы можете использовать функцию обратного вызова.setState(prevState => newState).

Может иметь несколько состояний в одном компоненте: вызывать несколько разuseState().

Ленивая инициализация удобна, когда служебные данные начального состояния велики. Вызывается с обратным вызовом, который вычисляет начальное состояниеuseState(computeInitialState), и этот обратный вызов выполняется только один раз при начальном рендеринге.

обязательно использоватьuseState()Следуйте правилам Хука.

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

Наконец, вы будете использоватьuseState()управлять простым состоянием. Для обработки более сложных состояний лучше использоватьuseReducer()крюк.


оригинал:Рисовая поездка avlutin.com/react-uses T…

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


Коммуникация (приглашаем вступить в группу, группа будет присылать красные конверты по рабочим дням, технология интерактивного обсуждения)

Статьи из серии галантерейных товаров резюмируются следующим образом: если вы чувствуете себя хорошо, нажмите «Звезда», добро пожаловать в группу, чтобы учиться друг у друга.

GitHub.com/QQ449245884…

Из-за нехватки места сегодняшний обмен только здесь. Если вы хотите узнать больше контента, вы можете отсканировать QR-код внизу каждой статьи, а затем подписаться на нашу общедоступную учетную запись WeChat, чтобы узнать больше информации и ценного контента.

clipboard.png