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

Next.js 13: React Context для управления состоянием

8 min read Frontend Обновлено 02 Jan 2026
Next.js 13: React Context для состояния
Next.js 13: React Context для состояния

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

Для кого эта статья

  • Фронтенд‑разработчики, которых интересует управление состоянием в приложениях на Next.js 13.
  • Тримеры, которые хотят интегрировать React Context без дополнительных библиотек.
  • Ревьюеры кода и девопс‑инженеры, отвечающие за перенос контекста между server- и client‑компонентами.

Ключевая идея

React Context предоставляет глобальное хранилище для данных, к которым нужен доступ из разных веток дерева компонентов. В Next.js 13 (app/) компоненты по умолчанию серверные, поэтому клиентские возможности контекста нужно пометить флагом “use client” и поместить провайдер в корневой layout, чтобы клиентские компоненты могли получить доступ к контексту.

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

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

Контекст не заменяет все решения для состояния. Это удобный инструмент для глобальных настроек и небольших коллекций данных. При частых и массовых обновлениях стоит рассмотреть специализированные библиотеки или техники оптимизации.

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

Почему это особенно важно в Next.js 13

Next.js 13 использует концепцию Server Components по умолчанию в директорие app/. Серверные компоненты рендерятся на сервере и не могут использовать клиентский стейт или хуки, такие как useState или useContext. Для клиентского поведения нужно явно указывать “use client” в файлах компонентов. При этом провайдер контекста должен оборачивать клиентские части приложения и располагаться там, где все клиентские компоненты могут его достать (обычно — корневой layout).

Важно: контекст не подходи для хранения чувствительных секретов (например, токенов в виде простого текста). Для авторизации предпочтительнее httpOnly cookies или сервер‑side хранение и проверка.

Быстрый старт: создание проекта Next.js

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

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

        `cd next-context-api`
    

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

        `npm run dev`
    

После этого можно реализовать простой todo‑app с использованием React Context API.

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

Файл провайдера централизует стейт и логику изменения. Создайте файл 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}  
      
  );  
};`
    

Пояснения к провайдеру:

  • initialState задаёт начальное состояние (пустой список todo).
  • reducer описывает действия: ADD_TODO, DELETE_TODO, EDIT_TODO. Это даёт предсказуемую логику изменений.
  • TodoContextProvider использует useReducer и предоставляет { state, dispatch } всем потомкам.

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

Чтобы все клиентские компоненты видели контекст, оберните children в корневом layout.

Откройте src/app/layout.js и замените шаблон следующим кодом.

        `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}  
        
      
  );  
}`
    

Теперь любой клиентский компонент в приложении сможет использовать TodoContext.

Создание компонента Todo

Импортируйте зависимости и пометьте компонент как клиентский.

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

Далее компонент и разметка:

        `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("");  
  };`
    

Эти функции диспатчат действия в reducer, который обновляет глобальный стейт.

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

Откройте src/app/page.js и замените содержимое на:

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

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

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

  • Подходит: глобальные настройки (тема, локаль), статус авторизации, небольшие списки данных, где частота обновлений невелика.
  • Не подходит: большие объёмы часто меняющегося состояния (много операций записи), потому что каждый update может триггерить повторный рендер множества компонентов. В таких случаях рассматривайте селекторы, мемоизацию или сторонние библиотеки.

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

  • Redux — для больших приложений со сложной логикой и временем жизни данных. Лучше для предсказуемости и инструментов (Redux DevTools).
  • Zustand — простая и перформантная библиотека с минимальной обвязкой.
  • Recoil / Jotai — атомарный подход к состоянию, хорош для локальных независимых состояний.
  • use-context-selector — оптимизация для уменьшения лишних рендеров при использовании контекста.

Короткий критерий выбора:

  • Нужна глобальная согласованность + инструменты отладки → Redux.
  • Лёгкость и простота → Zustand.
  • Много независимых кусочков состояния → Jotai / Recoil.
  • Минимальные зависимости → React Context + useReducer.

Оптимизация производительности

  • Разбивайте контексты по зонам ответственности: один контекст для темы, другой для todo, третий для сессии.
  • Используйте useMemo и React.memo для предотвращения ненужных перерендеров.
  • Рассмотрите библиотеку use-context-selector, чтобы подписываться только на нужную часть стейта.
  • По возможности минимизируйте объём объектов в контексте (передавайте примитивы или мемоизированные селекторы).

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

  • Не храните токены доступа в обычном React Context. Используйте httpOnly cookie или серверную сессию.
  • При передаче персональных данных учитывайте GDPR: ограничьте время хранения и доступ только уполномоченных сервисов.

Тестирование и критерии приёмки

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

  • Компонент Todo может добавлять, редактировать и удалять элементы; это проверяется unit‑тестами reducer и интеграционными тестами UI.
  • Провайдер доступен всем клиентским компонентам, нет ошибок при SSR/CSR.
  • Изменения в списке todo не вызывают избыточных рендеров в неподключённых компонентах.

Примеры тест‑кейсов:

  • Диспатч ADD_TODO увеличивает длину массива todos и добавляет новый элемент.
  • DELETE_TODO удаляет элемент по индексу.
  • EDIT_TODO заменяет элемент по индексу на новое значение.
  • При пустом вводе ADD_TODO не должен добавлять пустой элемент.

Рекомендованные инструменты: Jest для reducer, React Testing Library для интеграционных тестов, Cypress для E2E.

Role‑based чек‑листы

Разработчик:

  • Пометил клиентские файлы “use client”.
  • Разместил провайдер в корневом layout.
  • Написал unit‑тесты для reducer.

Ревьюер:

  • Проверил нежелательные перерендеры.
  • Проверил, что в контексте нет чувствительных данных.

DevOps:

  • Обеспечил корректное окружение сборки (NODE_ENV, секреты).
  • Добавил мониторинг ошибок на клиенте.

Методология быстрой отладки и отката

  1. Локально включите подробный лог reducer; воспроизведите сценарий.
  2. Отключите изменения по частям: замените новый reducer на прошлую версию и проверьте.
  3. Если баг на production — откатить релиз, опубликовать хотфикс и запустить тесты.

Миграционные подсказки

  • При переводе с pages/ на app/ проверьте, где находятся client‑компоненты, и добавьте “use client”.
  • Провайдеры, которым нужны клиентские хуки, должны быть в layout.js (или в отдельных провайдерах внутри клиентской части).

Короткая шпаргалка команд

  • Создать проект: npx create-next-app@latest next-context-api
  • Запуск: npm run dev
  • Формат кода: npm run format (если настроен)

Мини‑глоссарий

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

Часто задаваемые вопросы

Нужно ли всегда использовать “use client” для контекста?

Да, если внутри провайдера или потребителей используются клиентские хуки (useState, useContext). Server Components не поддерживают их.

Можно ли хранить токен авторизации в контексте?

Не рекомендуется. Токены лучше хранить в httpOnly cookie или обрабатывать на сервере.

Как избежать избыточных перерендеров при использовании Context?

Разделяйте контексты, мемоизируйте значения и используйте селекторы (use-context-selector).

Итог

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

Важное

  • Не используйте Context для секретов. Храните токены безопасно.
  • Помечайте файлы “use client” там, где используются клиентские хуки.

Краткое резюме в конце:

  • Поместите провайдер в src/app/layout.js.
  • Помечайте клиентские компоненты “use client”.
  • Используйте useReducer внутри провайдера для предсказуемости.
  • Разбивайте контексты и оптимизируйте подписки для производительности.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

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

Сохранить стандартные значки Windows при смене тем
Windows

Сохранить стандартные значки Windows при смене тем

Исправить Your device is offline в Windows
Windows

Исправить Your device is offline в Windows

Исправление ошибки Windows Online Troubleshooting Service
Windows

Исправление ошибки Windows Online Troubleshooting Service

Добавить меню «Выбрать» в контекстное меню Windows
Windows

Добавить меню «Выбрать» в контекстное меню Windows

Отобразить скрытый аккаунт Администратора в Windows
Windows

Отобразить скрытый аккаунт Администратора в Windows

No boot device found — как исправить
Windows

No boot device found — как исправить