Spec-Zone.ru › React 18

Добавление интерактивности

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

В этой главе

  • Как обрабатывать события, инициированные пользователем
  • Как сделать компоненты «помнящими» информацию с помощью состояния
  • Как React обновляет пользовательский интерфейс в двух фазах
  • Почему состояние не обновляется сразу после изменения
  • Как поставить в очередь несколько обновлений состояния
  • Как обновить объект в состоянии
  • Как обновить массив в состоянии

Обработка событий

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

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

export default function App() {
  return (
    <Toolbar
      onPlayMovie={() => alert('Playing!')}
      onUploadImage={() => alert('Uploading!')}
    />
  );
}

function Toolbar({ onPlayMovie, onUploadImage }) {
  return (
    <div>
      <Button onClick={onPlayMovie}>
        Play Movie
      </Button>
      <Button onClick={onUploadImage}>
        Upload Image
      </Button>
    </div>
  );
}

function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}

Хотите узнать об этом больше?

Прочитайте Обработка событий, чтобы узнать, как добавить обработчики событий.

Читать далее

Состояние: память компонента

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

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

const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);

Вот как галерея изображений использует и обновляет состояние при нажатии:

import { useState } from 'react';
import { sculptureList } from './data.js';

export default function Gallery() {
  const [index, setIndex] = useState(0);
  const [showMore, setShowMore] = useState(false);
  const hasNext = index < sculptureList.length - 1;

  function handleNextClick() {
    if (hasNext) {
      setIndex(index + 1);
    } else {
      setIndex(0);
    }
  }

  function handleMoreClick() {
    setShowMore(!showMore);
  }

  let sculpture = sculptureList[index];
  return (
    <>
      <button onClick={handleNextClick}>
        Next
      </button>
      <h2>
        <i>{sculpture.name} </i>
        by {sculpture.artist}
      </h2>
      <h3>
        ({index + 1} of {sculptureList.length})
      </h3>
      <button onClick={handleMoreClick}>
        {showMore ? 'Hide' : 'Show'} details
      </button>
      {showMore && <p>{sculpture.description}</p>}
      <img
        src={sculpture.url}
        alt={sculpture.alt}
      />
    </>
  );
}

Хотите узнать об этом больше?

Прочитайте Состояние: память компонента, чтобы узнать, как запомнить значение и обновить его при взаимодействии.

Читать далее

Рендеринг и подтверждение

Перед отображением компонентов на экране React должен их отрисовать. Понимание этапов этого процесса поможет вам думать о том, как выполняется ваш код, и объяснять его поведение.

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

  1. Инициирование отрисовки (передача заказа от клиента на кухню)
  2. Отрисовка компонента (приготовление заказа на кухне)
  3. Подтверждение в DOM (выдача заказа клиенту)
  1. React as a server in a restaurant, fetching orders from the users and delivering them to the Component Kitchen.
    Инициирование
  2. The Card Chef gives React a fresh Card component.
    Отрисовка
  3. React delivers the Card to the user at their table.
    Подтверждение

Иллюстрация предоставлена Рэйчел Ли Наборс

Хотите узнать об этом больше?

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

Читать далее

Состояние как моментальная фотография

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

console.log(count);  // 0
setCount(count + 1); // Request a re-render with 1
console.log(count);  // Still 0!

Это поведение помогает избежать скрытых ошибок. Вот небольшой чат-приложение. Попробуйте угадать, что произойдет, если вы нажмете «Отправить», а затем измените получателя на Боба. Чье имя отобразится в alert через пять секунд?

import { useState } from 'react';

export default function Form() {
  const [to, setTo] = useState('Alice');
  const [message, setMessage] = useState('Hello');

  function handleSubmit(e) {
    e.preventDefault();
    setTimeout(() => {
      alert(`You said ${message} to ${to}`);
    }, 5000);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        To:{' '}
        <select
          value={to}
          onChange={e => setTo(e.target.value)}>
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">Send</button>
    </form>
  );
}

Хотите узнать об этом больше?

Прочитайте Состояние как моментальная фотография, чтобы узнать, почему состояние кажется «зафиксированным» и неизменным внутри обработчиков событий.

Читать далее

Постановка в очередь последовательности обновлений состояния

Этот компонент содержит ошибку: нажатие «+3» увеличивает счет только один раз.

import { useState } from 'react';

export default function Counter() {
  const [score, setScore] = useState(0);

  function increment() {
    setScore(score + 1);
  }

  return (
    <>
      <button onClick={() => increment()}>+1</button>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <h1>Score: {score}</h1>
    </>
  )
}

Состояние как моментальная фотография объясняет, почему это происходит. Установка состояния запрашивает новую перерисовку, но не изменяет его в уже выполняемом коде. Таким образом, score продолжает быть 0 сразу после вызова setScore(score + 1).

console.log(score);  // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score);  // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score);  // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score);  // 0

Вы можете исправить это, передав функцию-обновления при установке состояния. Обратите внимание, как замена setScore(score + 1) на setScore(s => s + 1) исправляет кнопку «+3». Это позволяет поставить в очередь несколько обновлений состояния.

import { useState } from 'react';

export default function Counter() {
  const [score, setScore] = useState(0);

  function increment() {
    setScore(s => s + 1);
  }

  return (
    <>
      <button onClick={() => increment()}>+1</button>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <h1>Score: {score}</h1>
    </>
  )
}

Хотите узнать об этом больше?

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

Читать далее

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

Состояние может содержать любые типы значений JavaScript, включая объекты. Но не следует непосредственно изменять объекты и массивы, хранящиеся в состоянии React. Вместо этого, когда вам нужно обновить объект или массив, необходимо создать новый (или скопировать существующий), а затем обновить состояние, используя эту копию.

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

import { useState } from 'react';

export default function Form() {
  const [person, setPerson] = useState({
    name: 'Niki de Saint Phalle',
    artwork: {
      title: 'Blue Nana',
      city: 'Hamburg',
      image: 'https://i.imgur.com/Sd1AgUOm.jpg',
    }
  });

  function handleNameChange(e) {
    setPerson({
      ...person,
      name: e.target.value
    });
  }

  function handleTitleChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        title: e.target.value
      }
    });
  }

  function handleCityChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        city: e.target.value
      }
    });
  }

  function handleImageChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        image: e.target.value
      }
    });
  }

  return (
    <>
      <label>
        Name:
        <input
          value={person.name}
          onChange={handleNameChange}
        />
      </label>
      <label>
        Title:
        <input
          value={person.artwork.title}
          onChange={handleTitleChange}
        />
      </label>
      <label>
        City:
        <input
          value={person.artwork.city}
          onChange={handleCityChange}
        />
      </label>
      <label>
        Image:
        <input
          value={person.artwork.image}
          onChange={handleImageChange}
        />
      </label>
      <p>
        <i>{person.artwork.title}</i>
        {' by '}
        {person.name}
        <br />
        (located in {person.artwork.city})
      </p>
      <img
        src={person.artwork.image}
        alt={person.artwork.title}
      />
    </>
  );
}

Если копирование объектов в коде становится утомительным, вы можете использовать библиотеку, такую как Immer, чтобы сократить повторяющийся код:

{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "use-immer": "0.5.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "devDependencies": {}
}

Хотите узнать об этом больше?

Прочитайте Обновление объектов в состоянии, чтобы узнать, как правильно обновлять объекты.

Читать далее

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

Массивы — это еще один тип изменяемых объектов JavaScript, которые вы можете хранить в состоянии, и к которым следует относиться как к неизменяемым. Так же, как и с объектами, при обновлении массива, хранящегося в состоянии, необходимо создать новый (или скопировать существующий), а затем установить состояние, используя новый массив:

import { useState } from 'react';

const initialList = [
  { id: 0, title: 'Big Bellies', seen: false },
  { id: 1, title: 'Lunar Landscape', seen: false },
  { id: 2, title: 'Terracotta Army', seen: true },
];

export default function BucketList() {
  const [list, setList] = useState(
    initialList
  );

  function handleToggle(artworkId, nextSeen) {
    setList(list.map(artwork => {
      if (artwork.id === artworkId) {
        return { ...artwork, seen: nextSeen };
      } else {
        return artwork;
      }
    }));
  }

  return (
    <>
      <h1>Art Bucket List</h1>
      <h2>My list of art to see:</h2>
      <ItemList
        artworks={list}
        onToggle={handleToggle} />
    </>
  );
}

function ItemList({ artworks, onToggle }) {
  return (
    <ul>
      {artworks.map(artwork => (
        <li key={artwork.id}>
          <label>
            <input
              type="checkbox"
              checked={artwork.seen}
              onChange={e => {
                onToggle(
                  artwork.id,
                  e.target.checked
                );
              }}
            />
            {artwork.title}
          </label>
        </li>
      ))}
    </ul>
  );
}

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

{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "use-immer": "0.5.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "devDependencies": {}
}

Хотите узнать об этом больше?

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

Читать далее

Что дальше?

Перейдите по ссылке Обработка событий, чтобы начать чтение этой главы по страницам!

Или, если вы уже знакомы с этими темами, почему бы не прочитать о Управлении состоянием?

© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://react.dev/learn/adding-interactivity

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API