Гид по технологиям

Простое приложение счётчика на React — пошаговое руководство

6 min read Frontend Обновлено 24 Dec 2025
React: простой счётчик — пошаговое руководство
React: простой счётчик — пошаговое руководство

Аналоговые часы с минутной стрелкой, указывающей на 12, размытый фон

React — одна из самых популярных библиотек JavaScript для фронтенда. Многие команды используют React для создания интерактивных пользовательских интерфейсов. Небольшое пошаговое приложение счётчика — отличный способ понять фундаментальные принципы React и получить уверенность в использовании хуков и компонентов.

Что вы создадите

Наша цель — простое приложение счётчика со следующими возможностями:

  • Кнопка увеличения: прибавляет 1.
  • Кнопка уменьшения: вычитает 1.
  • Кнопка сброса: устанавливает значение в 0.

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

Ключевые понятия (кратко)

  • Компонент: самостоятельная часть интерфейса, которую можно переиспользовать.
  • State: данные компонента, которые влияют на рендер и могут меняться со временем.
  • Функциональный компонент: обычная JS-функция, возвращающая JSX.
  • Props: входные параметры компонента, переданные сверху.
  • Хук useState: встроенная функция для управления локальным состоянием в функциональном компоненте.

Репозиторий и лицензия

Код проекта доступен в репозитории на GitHub и распространяется под MIT-лицензией (проверьте репозиторий для деталей и ссылок).

Шаг 1 — Создание проекта

Откройте терминал и выполните:

npx create-react-app react-counter-app

После создания проекта запустите сервер разработки:

npm start

Откроется http://localhost:3000, и любые изменения в коде будут автоматически отображаться в браузере.

Шаг 2 — Каркас приложения

Откройте src/App.js и удалите стандартный код. Создайте базовый каркас приложения так:

import React, { useState } from "react";

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

  let incrementCount = () => {
    // реализация ниже
  };

  let decrementCount = () => {
    // реализация ниже
  };

  let resetCount = () => {
    // реализация ниже
  };

  return (
    

Count: {count}

); } export default App;

Пояснение: useState возвращает текущее значение и функцию для его обновления. В JSX фигурные скобки {count} означают: подставить значение переменной JavaScript.

Шаг 3 — Добавление кнопок и логики

Внутри блока .buttons добавим три использования компонента Button (его создадим отдельно):

Реализуем функции в App.js:

let incrementCount = () => {
  setCount(count + 1);
};

let decrementCount = () => {
  setCount(count - 1);
};

let resetCount = () => {
  setCount(0);
};

Создайте папку src/components и файл src/components/Button.js со следующим кодом:

import React from "react";

function Button(props) {
  let { action, title } = props;
  return ;
}

export default Button;

Важно: при импортировании в App.js используйте правильный путь и имя файла:

import Button from "./components/Button";

Здесь часто встречается опечатка (например, “Botton”); если приложение не собирается — проверьте имя файла и импорт.

Ниже — итоговый App.js (убедитесь, что путь к Button совпадает с файловой системой):

import React, { useState } from "react";
import Button from "./components/Button";

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

  let incrementCount = () => {
    setCount(count + 1);
  };

  let decrementCount = () => {
    setCount(count - 1);
  };

  let resetCount = () => {
    setCount(0);
  };

  return (
    

Count: {count}

); } export default App;

Советы по структуре и стилю кода

  • Используйте короткие функции и понятные названия (incrementCount, decrementCount и т.д.).
  • Деструктурируйте props сразу в аргументах, если компонент небольшой: function Button({ action, title }) { … }
  • Разделяйте компоненты по папкам согласно назначению (components/, pages/, hooks/).
  • Пишите минимальные тесты для ключевой логики (см. раздел «Критерии приёмки и тесты»).

Дополнительные улучшения и альтернативы

  1. useReducer вместо useState
  • Для более сложной логики обновления состояния (несколько типов действий) можно использовать useReducer — он делает обработку действий явной и тестируемой.

Пример минимального редьюсера:

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    case "reset":
      return { count: 0 };
    default:
      return state;
  }
}

const [state, dispatch] = useReducer(reducer, { count: 0 });
  1. Локальное хранение (localStorage)
  • Можно сохранять значение счётчика в localStorage для восстановления после перезагрузки страницы.
  • Не храните чувствительные данные в localStorage.
  1. Контекст (Context) для глобального состояния
  • Если счётчик должен использоваться в разных местах приложения, рассмотреть React Context или глобальные менеджеры состояния.
  1. Типизация
  • Используйте TypeScript или PropTypes для документирования типов и предотвращения багов.

Паттерны, когда счётчик «ломается» (примеры ошибок)

  • Многократное обновление state на основе устаревшего значения count при асинхронных операциях. Решение: использовать функциональную форму setState: setCount(prev => prev + 1).
  • Опечатки в путях импортов (Botton vs Button) — приложение не соберётся.
  • Изменение state напрямую (например, count = count + 1) — React не заметит изменений.

Тесты и критерии приёмки

Критерии приёмки

  • После загрузки приложения значение счётчика равно 0.
  • При клике на Increment значение увеличивается на 1.
  • При клике на Decrement значение уменьшается на 1.
  • При клике на Reset значение устанавливается в 0.

Минимальные тесты (пример с React Testing Library):

import { render, screen, fireEvent } from "@testing-library/react";
import App from "./App";

test("initial count is 0 and buttons work", () => {
  render();
  expect(screen.getByText(/Count:/)).toHaveTextContent("Count: 0");

  fireEvent.click(screen.getByText("Increment"));
  expect(screen.getByText(/Count:/)).toHaveTextContent("Count: 1");

  fireEvent.click(screen.getByText("Decrement"));
  expect(screen.getByText(/Count:/)).toHaveTextContent("Count: 0");

  fireEvent.click(screen.getByText("Reset"));
  expect(screen.getByText(/Count:/)).toHaveTextContent("Count: 0");
});

Критерии приёмки включают: корректный рендер, корректная реакция на события и отсутствие ошибок в консоли.

Чек-листы по ролям

Для разработчика:

  • Создана структура src/components
  • App.js содержит useState и функции управления
  • Button компонент переиспользуется
  • Код форматирован (Prettier/ESLint)
  • Типы указаны (PropTypes/TS)

Для QA:

  • Выполнены тесты на клики
  • Проверена доступность (aria-label для кнопок при необходимости)
  • Проверено поведение при быстрых кликах (стабильность)

Для ревьювера:

  • Нет опечаток в импортируемых путях
  • Не изменяется state напрямую
  • Логика вынесена в понятные функции

Отладка и распространённые баги

  • Ошибка «Module not found»: проверьте путь и регистр символов в имени файла.
  • Кнопки не работают: убедитесь, что onClick назначен корректно и функция не перезаписывается.
  • Непредсказуемое поведение при нескольких быстрых кликах: используйте функциональный setState setCount(prev => prev + 1) для гарантии корректного обновления.

Пример безопасного инкремента:

let incrementCount = () => {
  setCount(prev => prev + 1);
};

Доступность (a11y) и стили

  • Добавьте aria-label к кнопкам для скринридеров:
  • Стили (CSS) можно вынести в src/App.css или использовать CSS-модули.

Пример простого CSS:

.app { text-align: center; padding: 2rem; }
.buttons { display: flex; gap: 1rem; justify-content: center; }
button { padding: 0.5rem 1rem; font-size: 1rem; }

Производительность и масштабирование

  • Для простого счётчика оптимизаций не требуется. При росте приложения следите за количеством рендеров и передаваемых props.
  • Используйте React.memo для дорогих дочерних компонентов.

Безопасность и приватность

  • Приложение счётчика не обрабатывает чувствительные данные. Если вы сохраняете значение в localStorage — убедитесь, что не попадаете под правила обработки персональных данных, если в считанных данных будет идентифицируемая информация.

Короткая методология разработки (микро-SOP)

  1. Создать проект create-react-app.
  2. Сделать каркас App.js с useState.
  3. Создать Button компонент и подключить в App.
  4. Реализовать increment/decrement/reset.
  5. Добавить стили и a11y-атрибуты.
  6. Написать тесты и отдать на ревью.
  7. Закоммитить и опубликовать в репозиторий.

Когда стоит не использовать такой подход

  • Если логика состояния сложная (несколько типов действий и побочных эффектов), лучше выбрать useReducer или внешние менеджеры состояния.
  • Для глобально разделяемого состояния стоит применять Context или Redux/MobX.

Факто-бокс: ключевые шаги

  • Инициализация: npx create-react-app
  • Хук: useState для локального состояния
  • Компонент: Button как переиспользуемый элемент
  • Тесты: React Testing Library для проверки кликов

Примеры расширений (идеи)

  • Добавить ввод шага (step) — изменение на N, а не на 1.
  • Добавить историю изменений и возможность отмены (undo).
  • Синхронизация со сервером через API для совместного использования счётчика.

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

Это руководство даёт полный набор шагов для создания простого счётчика на React: от инициализации проекта до тестов и чек-листов для команд. Вы получили рабочий пример кода, рекомендации по улучшению и список распространённых ошибок с их решениями.

Важно: начальный счётчик — отличный учебный проект, который легко масштабировать и превращать в более сложную функциональность.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство