Preparei um caso de teste simples no Github para minha pergunta:
Em RouterLayout.jsx, uma consulta de mídia faz Outlet
desaparecer em telas estreitas, como você pode ver na captura de tela animada, onde arrasto a lateral do navegador para torná-la menor:
RootLayout.jsx
import { Outlet } from "react-router";
import { useMediaQuery } from "@react-hook/media-query";
import MasterList from "../components/MasterList";
export default function RootLayout() {
const isSmallScreen = useMediaQuery("(max-width: 768px)");
return (
<div
style={{
display: "flex",
justifyContent: "space-around",
alignItems: "flex-start",
}}
>
<MasterList />
{!isSmallScreen && (
<div>
<h3>Detail</h3>
<Outlet />
</div>
)}
</div>
);
}
Minha pergunta, por favor:
Em telas pequenas de celulares apenas a Lista Mestre deve ser exibida. E quando um Link for clicado ali, uma Página1 ou outras páginas deverão ser exibidas, com possibilidade de retornar à Lista Mestre. Isso ainda não funciona.
Em telas grandes de tablets e computadores, a Lista mestre e a Página1 ou outras são exibidas próximas uma da outra. Isso já funciona no meu código.
Devo adicionar algum atributo ao Link
s no MasterList.jsx abaixo?
MasterList.jsx
import { Link } from "react-router-dom";
const MasterList = () => {
const pages = [
{ id: 1, title: "Page 1" },
{ id: 2, title: "Page 2" },
{ id: 3, title: "Page 3" },
{ id: 4, title: "Page 4" },
];
return (
<div>
<h2>Master List</h2>
<nav>
<ul>
{pages.map((page) => (
<li key={page.id}>
<Link to={"/page" + page.id}>{page.title}</Link>
</li>
))}
</ul>
</nav>
</div>
);
};
export default MasterList;
Aplicativo.jsx
import {
Route,
RouterProvider,
createBrowserRouter,
createRoutesFromElements,
} from "react-router-dom";
import Page1 from "./pages/Page1";
import Page2 from "./pages/Page2";
import Page3 from "./pages/Page3";
import Page4 from "./pages/Page4";
import RootLayout from "./layouts/RootLayout";
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<RootLayout />}>
<Route path="page1" element={<Page1 />} />
<Route path="page2" element={<Page2 />} />
<Route path="page3" element={<Page3 />} />
<Route path="*" element={<Page4 />} />
</Route>
)
);
const App = () => {
return <RouterProvider router={router} />;
};
export default App;
Em tamanhos de visualização menores, onde
Outlet
não são renderizados, osRoute
componentes aninhados não têm mais um local para renderizar seuelement
conteúdo. Se entendi sua postagem corretamente, você deseja usarRootLayout
osOutlet
tamanhos de visualização maiores, não "móveis", e os tamanhos de visualização móveis, renderizadosRootLayout
como uma rota irmã em vez de uma rota pai, para que todas as outras rotas sejam acessíveis.Exemplo de refatoração:
Crie dois layouts raiz, móvel e não móvel.
Atualize
App
para usar o gancho de consulta de mídia e renderizar condicionalmente um layout raiz ou outro, e renderizar condicionalmenteMasterList
como uma rota de índice em telas menores.Alternativa
Uma alternativa pode ser utilizar o
useMatch
gancho para testar se a raiz"/"
é a rota e renderização atualmente correspondidaMasterList
. A lógica é um pouco mais complicada e um pouco menos DRY . A essência aqui é renderizar os tamanhos de visualização normaisMasterList
eOutlet
maiores, e nas visualizações móveis renderizar condicionalmenteMasterList
apenas se estiver na página inicial, caso contrário, renderizarOutlet
para as rotas aninhadas.Exemplo:
Não sei qual é a melhor abordagem para conseguir isso, mas é necessário incorporar o fato de que o Outlet renderiza rotas filhas no componente pai.
Eu exploraria useMatches para ver se você pode usá-lo para determinar se o componente Parent foi renderizado em
/parent
ou/parent/child
. Com essas informações, você poderia renderizar condicionalmente os elementos de navegação: