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

Управление состоянием в Next.js 13 с помощью React Context API

7 min read Frontend Обновлено 12 Apr 2026
Next.js 13: React Context для управления состоянием
Next.js 13: React Context для управления состоянием

Ноутбук с открытым кодом на столе в кафе рядом с растением

Next.js предоставляет несколько подходов к управлению состоянием. Некоторые из них требуют установки внешних библиотек, но React Context API встроен в React, поэтому он помогает снизить зависимость от внешних пакетов.

React Context позволяет удобно передавать данные через дерево компонентов, избавляя от проп-дриллинга. Это особенно полезно для глобального состояния: статус аутентификации пользователя, выбранная тема, языковые настройки и подобное.

Понимание React Context API

Перед тем как перейти к коду, важно понять, что такое React Context API и какую проблему он решает.

Props — простой способ передачи данных от родителя к потомкам. Они хорошо показывают, какие компоненты используют данные и как они текут вниз по дереву.

Однако когда компоненты глубоко вложены и всем нужно одни и те же данные, код может усложниться из‑за постоянной передачи props через промежуточные компоненты. Эту проблему называют prop drilling.

Экран ноутбука с кодом React и логотипом React

React Context решает эту задачу: вы создаёте централизованное хранилище данных (контекст), а компоненты получают к нему доступ напрямую. Это упрощает архитектуру и делает код более читабельным.

Важно: Context не заменяет всю логику управления состоянием — он подходит для «глобальных» данных. Для высоконагруженных динамических состояний или сложных структур состояния иногда нужны другие решения.

Вы можете найти код этого проекта в его репозитории на GitHub.

Начало работы в Next.js 13 с React Context API

Next.js Server Components дают возможность объединить интерактивность клиентских приложений с производительностью серверного рендеринга. В Next.js 13 Server Components включены по умолчанию в директории app. Поскольку серверные компоненты не могут использовать клиентские API напрямую, при интеграции клиентских библиотек (включая Context в клиентском режиме) возникает необходимость пометить файлы как клиентские.

Для этого в файлах клиентских компонентов нужно указать директиву “use client” вверху файла.

Для начала создайте проект Next.js 13 локально:

npx create-next-app@latest next-context-api

Перейдите в каталог проекта:

cd next-context-api

Запустите dev‑сервер:

npm run dev

Теперь можно создать простое приложение To‑Do, которое использует React Context для управления состоянием.

Создание провайдера контекста

Файл провайдера — это центр, где вы определяете глобальное состояние, редьюсер и методы обновления.

Создайте файл src/context/Todo.context.js и добавьте следующий код.

"use client"  
  
import React, { createContext, useReducer } from "react";  
  
const initialState = {  
  todos: [],  
};  
  
const reducer = (state, action) => {  
  switch (action.type) {  
    case "ADD_TODO":  
      return { ...state, todos: [...state.todos, action.payload] };  
  
    case "DELETE_TODO":  
      return { ...state, todos: state.todos.filter((todo, index) =>  
               index !== action.payload) };  
  
    case "EDIT_TODO":  
      const updatedTodos = state.todos.map((todo, index) =>  
               index === action.payload.index ? action.payload.newTodo : todo);  
      return { ...state, todos: updatedTodos };  
  
    default:  
      return state;  
  }  
};  
  
export const TodoContext = createContext({  
  state: initialState,  
  dispatch: () => null,  
});  
  
export const TodoContextProvider = ({ children }) => {  
  const [state, dispatch] = useReducer(reducer, initialState);  
  
  return (  
      
      {children}  
      
  );  
};

Этот код создаёт TodoContext с пустым массивом задач. Редьюсер обрабатывает три типа действий: ADD_TODO, DELETE_TODO и EDIT_TODO. Компонент TodoContextProvider оборачивает приложение и передаёт { state, dispatch } всем вложенным компонентам.

Ключевые понятия:

  • Context — контейнер для общих данных.
  • Provider — компонент, который делает эти данные доступными.
  • Reducer — чистая функция, описывающая, как состояние меняется по действию.

Добавление провайдера в приложение Next.js

Чтобы провайдер был доступен всем компонентам, подключите его в корневом layout. Откройте src/app/layout.js и оберните children в TodoContextProvider:

import './globals.css';  
import { TodoContextProvider } from "@/context/Todo.context";  
  
export const metadata = {  
  title: "Create Next App",  
  description: "Generated by create next app",  
};  
  
export default function RootLayout({  
  children  
}) {  
  return (  
      
        
        {children}  
        
      
  );  
}

После этого все клиентские компоненты, находящиеся внутри app, смогут использовать контекст.

Создание компонента To‑Do

Создайте src/components/Todo.js и пометьте файл как клиентский с “use client”.

Импорт и начало файла:

"use client"  
  
import { TodoContext } from "@/context/Todo.context";  
import React, { useContext, useState } from "react";  

Основной компонент (JSX):

export default function Todo() {  
  return (  
    

Todos

setTodoText(e.target.value)} style={{ marginBottom: 16}} placeholder="Enter a todo" />
    {state.todos.map((todo, index) => (
  • {index === editingIndex ? ( <> setEditedTodo(e.target.value)} /> ) : ( <> {todo} )}
  • ))}
); }

Переменные состояния и обработчики:

  const { state, dispatch } = useContext(TodoContext);  
  const [todoText, setTodoText] = useState("");  
  const [editingIndex, setEditingIndex] = useState(-1);  
  const [editedTodo, setEditedTodo] = useState("");  
  
  const handleAddTodo = () => {  
    if (todoText.trim() !== "") {  
      dispatch({ type: "ADD_TODO", payload: todoText });  
      setTodoText("");  
    }  
  };  
  
  const handleDeleteTodo = (index) => {  
    dispatch({ type: "DELETE_TODO", payload: index });  
  };  
  
  const handleEditTodo = (index, newTodo) => {  
    dispatch({ type: "EDIT_TODO", payload: { index, newTodo } });  
    setEditingIndex(-1);  
    setEditedTodo("");  
  };

Эти обработчики отправляют соответствующие действия в редьюсер контекста и обновляют локальное состояние формы.

Рендер компонента на странице

Импортируйте компонент на страницу. В файле src/app/page.js замените шаблонный код на:

import styles from './page.module.css'  
import Todo from '../components/Todo'  
  
export default function Home() {  
  return (  
    
) }

После этого приложение отображает To‑Do и позволяет управлять задачами через Context.

Когда Context не подходит

Important: React Context удобен, но имеет ограничения. Рассмотрите альтернативы если:

  • Большие объёмы частых обновлений: Context вызывает ререндеры всех потребителей при изменении значения. Это может привести к потерям производительности.
  • Сложные асинхронные потоки и сайд-эффекты: для них лучше подходят библиотеки с встроенной поддержкой шины событий и middleware (например, Redux Toolkit с Thunks/Sagas).
  • Нужна оптимизация селекторов и мемоизация для отдельных частей состояния.

Counterexamples/когда отказ от Context оправдан:

  • Приложение с тысячами элементов, где изменения касаются только узкой части состояния.
  • Необходимость сложного trace и time-travel отладки.

Альтернативные подходы

  • Redux Toolkit — для сложных, предсказуемых состояний с большим количеством логики.
  • Zustand — лёгкая и быстрая альтернатива с минимальным API.
  • Recoil/Jotai — атомарные состояния для модульности.
  • SWR/React Query — для данных, получаемых с сервера (кеширование, синхронизация, фоновые обновления).

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

Ментальные модели и эвристика выбора

  • Если данные нужны «всюду» (тема, авторизация, настройки) — Context подходит.
  • Если изменение данных редкое — Context удобен.
  • Если изменения частые и касаются узкой части UI — выбирайте локальное состояние или специализированные менеджеры.

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

  • Когда использовать Context: для 5–10 глобальных сущностей (тема, язык, пользователь, корзина, настройки). (Качественный ориентир.)
  • Производительность: при больших состояниях группируйте данные по контекстам (несколько провайдеров вместо одного монолитного).
  • Архитектура: держите редьюсер чистым и предсказуемым — это облегчит тестирование.

Чек-лист для разработчика

  • Пометить клиентские файлы директивой “use client”.
  • Создать отдельный каталог для контекстов (src/context).
  • Разбивать глобальное состояние на несколько контекстов по зонам ответственности.
  • Покрыть редьюсер unit-тестами.
  • Не хранить в контексте нестабильные объекты (функции без мемоизации).

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

  • Приложение рендерит компонент To‑Do и корректно добавляет, редактирует и удаляет задачи.
  • Контекст доступен из клиентских компонентов, обёрнутых провайдером в layout.
  • Отсутствует ненужный prop drilling для глобальных данных.
  • Производительность приемлема: изменение одного todo не приводит к заметным замедлениям.

План миграции к Context (микроплан)

  1. Выделить данные, которые действительно нужны глобально.
  2. Создать контекст и провайдер с минимальным initialState.
  3. Обернуть app в провайдер и постепенно переводить компоненты с props на context.
  4. Покрыть поведение редьюсера тестами.
  5. Оптимизировать: разделить контексты, мемоизировать селекторы.

Тест-кейсы и приёмка

  • Добавление: при вводе текста и клике “Add” задача появляется в списке и в state.todos.
  • Удаление: при клике “Delete” задача исчезает и индекс корректно применяется.
  • Редактирование: в режиме редактирования поле сохраняет новое значение по клику “Save”.
  • Граничные условия: пустая строка не добавляется; индексы вне диапазона игнорируются.

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

  • Context не должен хранить секреты (пароли, токены) в виде plain text, если есть риск утечки в клиентском коде.
  • Для авторизации храните токены в безопасном месте (HTTP-only cookies) и передавайте в контексте только метаданные пользователя (имя, роли).
  • Для GDPR: если context содержит персональные данные, обеспечьте явное управление сроками хранения и удалением.

Совместимость и советы по миграции Next.js 13

  • В app‑директории серверные компоненты по умолчанию. Клиентские компоненты обязаны начинаться с “use client”.
  • Провайдеры контекста, использующие клиентский API, должны быть клиентскими компонентами и размещены внутри корневого layout, если их должны видеть все страницы.
  • Разделяйте провайдеры: вместо одного глобального создавайте провайдеры для независимых областей (AuthProvider, ThemeProvider, TodoProvider).

Рекомендации по отладке

  • Используйте React DevTools — вкладка Context показывает провайдеры и потребителей.
  • Логируйте actions в редьюсере для отслеживания последовательности изменений.
  • Добавьте unit-тесты для reducer: проверяйте работу ADD_TODO, DELETE_TODO, EDIT_TODO.

Краткое объявление для команды (100–200 слов)

Мы внедрили React Context в Next.js 13 для управления глобальным состоянием To‑Do приложения. Контекст упрощает доступ к данным без проп-дриллинга и позволяет централизованно управлять списком задач с помощью редьюсера (ADD_TODO, DELETE_TODO, EDIT_TODO). Провайдер зарегистрирован в корневом layout, а клиентские компоненты помечены директивой “use client”. При внедрении мы учли производительность: при необходимости состояние можно разделять на несколько провайдеров. Для сложной логики можно комбинировать Context с Redux или Zustand. Просьба протестировать сценарии добавления, редактирования и удаления задач, а также оценить влияние на ререндеры в ваших ключевых страницах.

Итог

React Context — удобный инструмент для простого и понятного глобального состояния. В Next.js 13 важно корректно помечать клиентские компоненты и располагать провайдер в корневом layout. Для больших и динамичных приложений рассматривайте гибридные архитектуры с более специализированными менеджерами состояния.

Summary:

  • Context прост для внедрения и подходит для глобальных настроек.
  • Разбивайте состояние на несколько контекстов для производительности.
  • Тестируйте редьюсер и отслеживайте ререндеры.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

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

ChatGPT для рабочих процессов и продуктивности
Продуктивность

ChatGPT для рабочих процессов и продуктивности

Карта Payoneer MasterCard: заказ и использование
Платежи

Карта Payoneer MasterCard: заказ и использование

SSH на Linux: настройка и безопасный доступ
Linux

SSH на Linux: настройка и безопасный доступ

Как конвертировать PDF в PowerPoint
Инструменты

Как конвертировать PDF в PowerPoint

DISM в Windows 11: восстановление образа и файлов
Windows

DISM в Windows 11: восстановление образа и файлов

Графические Linux‑приложения в Windows 11 через WSL
Инструменты

Графические Linux‑приложения в Windows 11 через WSL