Лейауты страниц
Это руководство рассматривает абстракцию лейаута страницы — когда несколько страниц имеют одинаковую структуру, отличаясь только основным содержимым.
Вашего вопроса нет в этом руководстве? Напишите свой вопрос, оставив отзыв к этой статье (синяя кнопка справа), и мы рассмотрим возможность расширения этого руководства!
Простой лейаут
Самый простой лейаут можно увидеть прямо на этой странице. Он имеет хэдер с навигацией по сайту, два сайдбара и футер с внешними ссылками. Здесь нет сложной бизнес-логики, и единственные динамические части — это сайдбары и переключатели справа в хэдере. Такой лейаут можно разместить целиком в shared/ui
или в app/layouts
, с заполнением контента сайдбаров через пропы:
import { Link, Outlet } from "react-router-dom";
import { useThemeSwitcher } from "./useThemeSwitcher";
export function Layout({ siblingPages, headings }) {
const [theme, toggleTheme] = useThemeSwitcher();
return (
<div>
<header>
<nav>
<ul>
<li> <Link to="/">Home</Link> </li>
<li> <Link to="/docs">Docs</Link> </li>
<li> <Link to="/blog">Blog</Link> </li>
</ul>
</nav>
<button onClick={toggleTheme}>{theme}</button>
</header>
<main>
<SiblingPageSidebar siblingPages={siblingPages} />
<Outlet /> {/* Здесь будет основное содержимое страницы */}
<HeadingsSidebar headings={headings} />
</main>
<footer>
<ul>
<li>GitHub</li>
<li>Twitter</li>
</ul>
</footer>
</div>
);
}
export function useThemeSwitcher() {
const [theme, setTheme] = useState("light");
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
useEffect(() => {
document.body.classList.remove("light", "dark");
document.body.classList.add(theme);
}, [theme]);
return [theme, toggleTheme] as const;
}
Код сайдбаров оставлен читателю в качестве упражнения 😉.
Использование виджетов в лейауте
Иногда есть необходимость включить в лейаут определенную бизнес-логику, особенно если вы используете глубоко вложенные маршруты с роутером типа React Router. Тогда вы не можете хранить лейаут в Shared или в Widgets из-за правила импорта для слоёв:
Модуль в слайсе может импортировать другие слайсы только в том случае, если они расположены на слоях строго ниже.
Прежде чем обсуждать решения, нам нужно обсудить, действительно ли это проблема. Вам действительно нужен этот лейаут, и если да, действительно ли он должен быть виджетом? Если блок бизнес-логики, про который идёт речь, используется на 2-3 страницах, и лейаут просто является небольшой обёрткой для этого виджета, рассмотрите один из этих двух вариантов:
-
Напишите ваш лейаут прямо в коде роутера на уровне App
Это отлично подходит для роутеров, поддерживающих вложенность, потому что вы можете группировать определенные маршруты и применять нужный лейаут только к ним. -
Просто скопируйте его
Желание абстрагировать код часто переоценено. Это особенно верно для лейаутов, потому что они редко меняются. В какой-то момент, если одна из этих страниц потребует изменений, вы можете просто внести изменения, не затрагивая другие страницы. Если вы беспокоитесь, что кто-то может забыть обновить другие страницы, всегда можно оставить комментарий, описывающий отношения между страницами.
Если ни один из вышеперечисленных вариантов не подходит, есть два решения для включения виджета в лейаут:
-
Используйте render props или слоты
Большинство фреймворков позволяют передавать часть UI внешне. В React это называется render props, в Vue — слоты. -
Переместите лейаут на уровень App
Вы также можете хранить свой лейаут на уровне App, например, вapp/layouts
, и комбинировать любые виджеты, которые вам нужны.
Дополнительные материалы
- Пример создания лейаута с аутентификацией с помощью React и Remix (аналогичен React Router) можно найти в туториале.