Как добавить пользовательский класс в элемент тела для некоторых маршрутов — nexjts

#javascript #next.js

Вопрос:

Я хочу добавить свой пользовательский класс на некоторые страницы. например

все страницы должны быть fixed-header исключением этого класса, это маршруты:

 /cart/step-1 

/login
 

этот класс добавляет или удаляет элемент тела.

 <body className="bg-gray fixed-header" 
 

но я не знаю, как я могу справиться с этим сценарием?

Ответ №1:

Создайте пользовательский _document.js каталог и _app.js в своем каталоге страниц.

Небольшая утилита для проверки наличия класса в теле (чтобы избежать дублирования класса, благодаря предложению @juliomalves):

 // ./utils/hasClasses
const hasClasses = () =>
  document.body.classList.contains("bg-gray") amp;amp;
  document.body.classList.contains("fixed-header");
export default hasClasses;
 

Рендеринг на стороне сервера

В _document.js , используйте __NEXT_DATA__ реквизит, чтобы получить доступ к текущей странице, проверьте, есть ли страница в разрешенных маршрутах, и добавьте классы в тело.

 import Document, { Html, Head, Main, NextScript } from "next/document";

class MyDocument extends Document {

  // Add more routes here if you want to use the same classes  
  allowedRoutes = ["/login", "/cart/step-1"];

  getColor() {
    const { page } = this.props?.__NEXT_DATA__;
    if (this.allowedRoutes.includes(page))
      return "bg-gray fixed-header";
    return "";
  }

  render() {
    return (
      <Html>
        <Head />
        <body className={this.getColor()}>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;
 

Приведенный выше код всегда выполняется на сервере. Классы не добавляются к телу при навигации на стороне клиента.

Рендеринг на стороне клиента

Чтобы устранить вышеуказанную проблему, используйте ту же логику в _app.js in a useEffect , чтобы она добавляла правильный класс при визуализации на клиенте.

 import { useEffect } from "react";
import { useRouter } from "next/router";
import "../styles.css";
import hasClasses from "./utils/hasClasses";

function MyApp({ Component, pageProps }) {

  const { pathname: page } = useRouter();
  const allowedRoutes = ["/login", "/cart/step-1"];

  useEffect(() => {
    if (!hasClasses() amp;amp; allowedRoutes.includes(page))
      document.body.className  = "bg-gray fixed-header";
    else if (hasClasses()) {
      // Don't want the styles in other pages, remove if exists.
      // Up to your implementation on how you want to handle this.
      document.body.classList.remove("bg-gray");
      document.body.classList.remove("fixed-header");
    }
  });
  return <Component {...pageProps} />;
}

export default MyApp;
 

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

Комментарии:

1. Хорошее решение SSR с использованием __NEXT_DATA__ . Просто небольшая придирка к коду CSR, возможно, вам захочется проверить bg-gray fixed-header , существуют ли классы, прежде чем добавлять их на body страницу, когда она находится в разрешенных маршрутах. Это предотвращает добавление повторяющихся классов, например, при переходе от /login к /cart/step-1 .

Ответ №2:

Самое простое и быстрое решение. Добавьте этот код в каждый компонент, в котором вам нужны разные классы <body> .

 useEffect( () => { document.querySelector("body").classList.add("bg-gray fixed-header") } );