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