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

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/).
- Пишите минимальные тесты для ключевой логики (см. раздел «Критерии приёмки и тесты»).
Дополнительные улучшения и альтернативы
- 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 });- Локальное хранение (localStorage)
- Можно сохранять значение счётчика в localStorage для восстановления после перезагрузки страницы.
- Не храните чувствительные данные в localStorage.
- Контекст (Context) для глобального состояния
- Если счётчик должен использоваться в разных местах приложения, рассмотреть React Context или глобальные менеджеры состояния.
- Типизация
- Используйте 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)
- Создать проект create-react-app.
- Сделать каркас App.js с useState.
- Создать Button компонент и подключить в App.
- Реализовать increment/decrement/reset.
- Добавить стили и a11y-атрибуты.
- Написать тесты и отдать на ревью.
- Закоммитить и опубликовать в репозиторий.
Когда стоит не использовать такой подход
- Если логика состояния сложная (несколько типов действий и побочных эффектов), лучше выбрать useReducer или внешние менеджеры состояния.
- Для глобально разделяемого состояния стоит применять Context или Redux/MobX.
Факто-бокс: ключевые шаги
- Инициализация: npx create-react-app
- Хук: useState для локального состояния
- Компонент: Button как переиспользуемый элемент
- Тесты: React Testing Library для проверки кликов
Примеры расширений (идеи)
- Добавить ввод шага (step) — изменение на N, а не на 1.
- Добавить историю изменений и возможность отмены (undo).
- Синхронизация со сервером через API для совместного использования счётчика.
Краткое резюме
Это руководство даёт полный набор шагов для создания простого счётчика на React: от инициализации проекта до тестов и чек-листов для команд. Вы получили рабочий пример кода, рекомендации по улучшению и список распространённых ошибок с их решениями.
Важно: начальный счётчик — отличный учебный проект, который легко масштабировать и превращать в более сложную функциональность.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone