Как использовать Redux в Next.js

Автор Мохаммад Фейсал✏️

Redux — одно из самых популярных решений для управления состояниями в экосистеме React. В настоящее время существует множество альтернатив, но Redux по-прежнему остается самым надежным и широко используемым инструментом.

По этой причине многие проекты, использующие Next.js, хотят воспользоваться преимуществами Redux. Но использование Redux в приложении Next имеет несколько особенностей, и настройка не всегда проста. Поэтому в этой статье мы расскажем вам о том, как настроить проект Next с Redux.

Содержание

  • Почему вы должны использовать Redux с Next.js?
  • Создание примера приложения с Next.js и Redux
  • Использование хранилища Redux
  • Сохранение состояния в Next.js

Почему вы должны использовать Redux с Next.js?

Существует множество причин, по которым вы можете захотеть использовать Redux в приложении Next. Давайте рассмотрим некоторые из них.

Совместное использование состояния

Обычно центральное состояние используется для управления общими данными между компонентами в дереве. В React данные передаются только вниз, что означает, что вы можете передать данные от родительского компонента к дочернему компоненту.

Это ограничение иногда усложняет работу, поскольку компоненты могут находиться не рядом в дереве компонентов, и даже может не быть пути от родителя к ребенку.

В этом случае использование общего хранилища, в которое оборачиваются все компоненты, имеет полный смысл, и вы можете рассмотреть Redux.

Redux очень мощный

Redux очень силен как решение для управления состоянием. Он существует уже давно, поэтому имеет отличную поддержку сообщества.

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

Все знают Redux

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

Это означает, что даже если вы работаете в компании, которая создает новый проект на Next, вас все равно могут заставить использовать Redux, так что будет хорошей идеей научиться использовать его, исходя только из популярности.

Создание примера приложения с Next.js и Redux

Сегодня мы создадим простое приложение, которое отслеживает, вошел ли пользователь в систему или нет, а затем, исходя из этого состояния, изменяет текст над кнопкой.

Цель этого проекта — продемонстрировать, как использовать Redux, поэтому я упрощаю задачу, чтобы мы могли сосредоточиться на интеграции Redux с Next. Далее у нас есть два варианта. Мы можем использовать обычный Redux, или мы можем использовать Redux Toolkit.

Redux используется во многих старых проектах, но рекомендуется использовать Redux Toolkit, так как в нем сокращено большое количество шаблонного кода и улучшена производительность. Однако настройки для обоих вариантов практически одинаковы.

Давайте создадим стартовый проект, выполнив следующую команду:

yarn create next-app --typescript
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы можете увидеть проект в действии, запустив yarn dev и посетив http://localhost:3000/ в браузере.

Установка зависимостей

Давайте установим необходимые зависимости для Redux Toolkit:

yarn add @reduxjs/toolkit react-redux
Вход в полноэкранный режим Выход из полноэкранного режима

Поскольку мы используем Next, нам понадобится дополнительный пакет, который позаботится о рендеринге на стороне сервера:

yarn add next-redux-wrapper
Войти в полноэкранный режим Выйти из полноэкранного режима

Создание фрагмента

Давайте создадим новую папку store и создадим в ней файл authSlice.ts. В официальной документации слайс определяется как: «набор логики и действий Redux reducer для одной функции в вашем приложении».

Мы поместим логику для нашего authState внутри этого файла authSlice.ts:

import { createSlice } from "@reduxjs/toolkit";
import { AppState } from "./store";
import { HYDRATE } from "next-redux-wrapper";

// Type for our state
export interface AuthState {
  authState: boolean;
}

// Initial state
const initialState: AuthState = {
  authState: false,
};

// Actual Slice
export const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {

    // Action to set the authentication status
    setAuthState(state, action) {
      state.authState = action.payload;
    },

    // Special reducer for hydrating the state. Special case for next-redux-wrapper
    extraReducers: {
      [HYDRATE]: (state, action) => {
        return {
          ...state,
          ...action.payload.auth,
        };
      },
    },

  },
});

export const { setAuthState } = authSlice.actions;

export const selectAuthState = (state: AppState) => state.auth.authState;

export default authSlice.reducer;
Вход в полноэкранный режим Выход из полноэкранного режима

Это простой фрагмент. Слайс для любого обычного React-приложения, использующего Redux, будет выглядеть именно так. Для Next пока нет ничего особенного.

Единственное, что мы здесь делаем, это определяем authState в нашем магазине и создаем действие для установки authState под названием setAuthState.

В строке 27 вы заметите специальный редуктор, который мы добавляем сюда под названием HYDRATE. Обработчик действия HYDRATE должен правильно согласовать гидратированное состояние поверх существующего состояния (если таковое имеется).

В принципе, когда происходит обновление страницы, если вы переходите с одной страницы на другую, или вызываются функции getStaticProps или getServerSideProps, в этот момент будет отправлено действие HYDRATE. payload этого действия будет содержать состояние на момент генерации статики или рендеринга на стороне сервера, поэтому ваш reducer должен правильно объединить его с существующим состоянием клиента.

Создание хранилища

Далее создайте файл store.ts для создания магазина и добавьте туда наш authSlice:

import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
import { authSlice } from "./authSlice";
import { createWrapper } from "next-redux-wrapper";

const makeStore = () =>
  configureStore({
    reducer: {
      [authSlice.name]: authSlice.reducer,
    },
    devTools: true,
  });

export type AppStore = ReturnType<typeof makeStore>;
export type AppState = ReturnType<AppStore["getState"]>;
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  AppState,
  unknown,
  Action
>;

export const wrapper = createWrapper<AppStore>(makeStore);
Войдите в полноэкранный режим Выход из полноэкранного режима

Обратите внимание на строку 22, где мы экспортируем специальную функцию wrapper. Эта обертка устраняет необходимость в Provider, который мы бы использовали в обычном React-приложении.

Обновление приложения

Нам осталось сделать еще одну вещь, чтобы завершить настройку нашей архитектуры Redux. Откройте файл _app.tsx и оберните наш компонент следующим образом:

import "../styles/globals.css";
import type { AppProps } from "next/app";
import { wrapper } from "../store/store";

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default wrapper.withRedux(MyApp);
Вход в полноэкранный режим Выйти из полноэкранного режима

Обратите внимание в строке 9, что мы оборачиваем наш компонент с помощью withRedux. Мы можем обернуть и отдельные страницы, но это не рекомендуется; при переходе от одной страницы к другой, если эта страница не обернута, произойдет сбой.

Использование магазина Redux

Наша установка Redux завершена! Давайте используем наш магазин Redux внутри страницы index.tsx следующим образом:

import type { NextPage } from "next";
import { selectAuthState, setAuthState } from "../store/authSlice";
import { useDispatch, useSelector } from "react-redux";

const Home: NextPage = () => {
  const authState = useSelector(selectAuthState);
  const dispatch = useDispatch();
  return (
    <div>
      <div>{authState ? "Logged in" : "Not Logged In"}</div>
      <button
        onClick={() =>
          authState
            ? dispatch(setAuthState(false))
            : dispatch(setAuthState(true))
        }
      >
        {authState ? "Logout" : "LogIn"}
      </button>
    </div>
  );
};

export default Home;
Вход в полноэкранный режим Выйти из полноэкранного режима

Любое хранилище Redux имеет две основные цели: чтение и обновление.

В строке 6 видно, что мы читаем состояние, используя функцию useSelector, предоставляемую react-redux.

У нас есть кнопка, на которой мы можем переключить authState, и на основе этого мы изменяем текст на кнопке.

Сохранение состояния в Next.js

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

Но если вы обновите страницу, то увидите, что состояние не сохраняется. Это происходит потому, что в Next каждая страница рендерится по требованию, а значит, при переходе с одной страницы на другую предыдущее состояние исчезнет.

В данном случае, если пользователь вошел в систему, то при переходе на другую страницу он будет автоматически выходить из системы, так как начальное значение authState определено как false.

Чтобы решить эту проблему, воспользуемся функцией-оберткой, которую мы создали ранее, и воспользуемся специальной функцией Next getServerSideProps, так как она будет вызываться при каждой загрузке страницы.

Давайте добавим следующий код в наш файл index.tsx:

export const getServerSideProps = wrapper.getServerSideProps(
  (store) =>
    async ({ params }) => {
      // we can set the initial state from here
      // we are setting to false but you can run your custom logic here
      await store.dispatch(setAuthState(false)); 
      console.log("State on server", store.getState());
      return {
        props: {
          authState: false,
        },
      };
    }
);
Вход в полноэкранный режим Выйти из полноэкранного режима

Здесь мы генерируем начальное состояние внутри функции getServerSideProps, поэтому даже если вы обновите страницу, вы увидите, что значения состояния остаются неизменными.

Заключение

Вот как вы можете интегрировать Redux в приложение Next! Вы можете найти репозиторий GitHub для этого проекта здесь. Я также рекомендую вам ознакомиться с документацией next-redux-wrapper, чтобы узнать больше о других вариантах использования.

Хорошего дня!


LogRocket: Полная видимость производственных приложений Next.js

Отладка приложений Next может быть сложной задачей, особенно когда пользователи сталкиваются с проблемами, которые трудно воспроизвести. Если вы заинтересованы в мониторинге и отслеживании состояния Redux, автоматическом выявлении ошибок JavaScript, отслеживании медленных сетевых запросов и времени загрузки компонентов, попробуйте LogRocket.

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

Пакет промежуточного ПО LogRocket Redux добавляет дополнительный уровень видимости пользовательских сессий. LogRocket регистрирует все действия и состояние ваших хранилищ Redux.

Модернизируйте отладку приложений Next.js — начните мониторинг бесплатно.

Оцените статью
devanswers.ru
Добавить комментарий