Мини-приложение: Счетчик нажатий

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

Подготовка

Мы создали заготовку нашего приложения и очистили ее от всего демонстрационного кода. Теперь мы готовы к тому, чтобы начать писать своё приложение. Каждое приложение мы будем создавать в отдельной папке внутри src (таковы правила), а потом "подключать" их в App.jsx. Таким образом будет легко вернуться и подсмотреть примеры кода из прошлых приложений.

Добавим в наш проект папку click-counter , а внутри неё создадим файл CounterApp.jsx.

Внутри CounterApp.jsx создадим компонент нашего приложения. Пока это просто кнопка:

import React from 'react';

export function CounterApp() {
  return (
    <button>Click me!</button>
  );
}

Строка с import React ... — очень важная. При сборке приложения весь наш JSX-код преобразуется в обычный JavaScript, которому нужен импортированный модуль React. При создании компонентов не забывай добавлять эту строчку вверху файла (необязательно на самом верху, главное, чтобы она была).

Внутри App.jsx добавим наш счетчик:

import React from "react";
import "./App.css";
import {CounterApp} from './click-counter'; // Не забудь импортировать его!

function App() {
  return <div className="App">
    <CounterApp/>
  </div>;
 }

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

Нам нужно хранить переменную-счетчик, и увеличивать ее при каждом нажатии на переменную.

Для того, чтобы хранить состояние, в Реакте есть функция useState. Импортируем ее из модуля react и вставляем в наше приложение:

import React, {useState} from "react";

export function CounterApp() {
  const [counter, setCounter] = useState(0);

  return (
    <button>Click me!</button>
  );
}

Обрати внимание на то, как странно выглядит теперь импорт. React импортируется default-импортом, useState — обычным, их можно комбинировать.

useState принимает изначальное значение (0) и возвращает массив [текущее_значение, функция_для_обновления_значения], который в нашем коде "распадается" на counter и setCounter соответственно.

Сделаем так, что рядом с надписью отображается счетчик:

return <button>Click me! {counter}</button>

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

Теперь добавим функцию, которая будет обработчиком нажатия на кнопку. Внутри нашей функции создадим еще одну 😱:

import React, {useState} from "react";

export function CounterApp() {
  const [counter, setCounter] = useState(0);

  function handleClick() {
   setCounter(counter + 1);
  }
  
  return (
    <button>Click me!</button>
  );
}

Будучи вызванной, эта функция установит значение counter в counter + 1. Теперь надо сделать так, чтобы обработчик increment вызывался при нажатии на кнопку:

return (
  <button onClick={handleClick}>Click me!</button>
);

Смотрим в браузер, кликаем мышкой по кнопке!

Что здесь происходит

HTML-элементы могут создавать события. Событий очень много, но два самых главных — это click (клик мышкой по элементу) и change (например, изменение текста в поле ввода).

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

Функция вызывает другую функцию, setCounter, которая обновляет значение счетчика, и говорит React-у о том, что компонент надо перерисовать, так как состояние изменилось. Именно поэтому мы не можем просто завести переменную counter и писать counter = counter + 1.

Во время перерисовки реакт вызывает нашу функцию App, однако в этот раз counter уже будет иметь новое значение, и на кнопке уже будет соответствующий текст.

Множество счетчиков

Один счетчик — это хорошо, а два — лучше.

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

Добавь в App еще несколько счетчиков и покликай их в браузере. Как видишь, у каждого из них свое собственное внутреннее состояние.

Props — Свойства компонента

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

Добавим к нашим счетчикам имена:

<Counter name="Красные машины" />

(проделай то же самое с остальными счетчиками)

Теперь нам надо сделать так, чтобы компонент счетчика считывал этот параметр и отображал его вместо "Click me!"

return (
  <button onClick={onClick}>
    {props.name} {counter}
  </button>
);

props — это объект, содержащий в себе все параметры, передаваемые в компонент. Параметр name="Красные машины" будет доступен внутри компонента как props.name.

Проверь в браузере, что у всех счетчиков разные имена и они считают по отдельности

Задание: Мы можем увеличивать значения счетчиков. Теперь надо сделать так, чтобы счетчики можно было уменьшать. Переделай компонент счетчика так, что бы он выглядел примерно так:

Текст счетчика: 123 [-] [+]

Last updated