Reputation: 4124
I'm using ReachUI Dialog
to render a Dialog (Modal).
The Dialog
is routable at the route products/create/
, as you can see in the code below.
Is it possible to render both the ProductsTable
(which is located at the parent route products/
) and the Dialog
, when I route to products/create
so that I can see the ProductsTable
component in the background of the modal?
I'm hoping to achieve this with react-router
.
This is what the code looks like now:
...
import { Switch, Route, useRouteMatch, match, useHistory, } from "react-router-dom";
import { Dialog } from "@reach/dialog";
export function ProductsPage() {
const { url }: match = useRouteMatch();
const { push } = useHistory();
const gotToCreateProduct = () => push(`${url}/create`);
return (
<Switch>
<Route exact path={url}>
<Page title="Products" onCreateButtonClick={gotToCreateProduct}>
<ProductsTable></ProductsTable>
</Page>
</Route>
<Route path={`${url}/create`}>
<Dialog isOpen={true} onDismiss={() => push(url)}>
<ProductForm></ProductForm>
</Dialog>
</Route>
</Switch>
);
}
Upvotes: 8
Views: 13784
Reputation: 1476
<BrowserRouter>
<Routes>
<Route path="/home" element={<Home />}>
<Route path="modal" element={<Modal />} />
</Route>
</Routes>
</BrowserRouter>
And inside the Home component add an Outlet;
import { Outlet } from "react-router-dom";
export default function Home(){
return(
<>
Home Code is here
<Outlet />
</>
)
}
so now, whenever that route /home/modal
is opened, it'll open the modal by default. Make sure to keep the prop isOpen
true by default as the rendering will be controlled by the react router now.
Upvotes: 10
Reputation: 779
@Akshay K Nair's answer is almost perfect, just wrong position of <Outlet />
. The correct use of <Outlet />
is to have the parent router component render it (read more here). Check out this React Router Dom v6 example:
export const router = createBrowserRouter([
{
path: "/",
element: <Home />,
children: [
{
path: "/:id",
element: (
<ModalRoute>
<Detail />
</ModalRoute>
),
},
],
},
])
const Home = () => {
return (
<>
Insert parent code
<Outlet />
</>
)
}
const ModalRoute = ({ children }) => {
const [opened, setOpened] = useState(false)
const location = useLocation()
const navigate = useNavigate()
useEffect(() => {
const id = location.pathname.split("/")[1]
if (id) {
setOpened(true)
}
}, [location.pathname])
const handleClose = () => {
navigate("/")
setOpened(false)
}
return (
<Modal opened={opened} onClose={handleClose}>
{children}
</Modal>
)
}
Upvotes: 9
Reputation: 4124
Figured it out myself,
basically you just have to put 2 Switch
components next to each other, and remove the exact
attribute of the parent Route
.
This way, both Switch
es will have a match and render their routes.
Makes sense & it works.
return (
<>
<Switch>
<Route path={url}>
<Page title="Products" onCreateButtonClick={gotToCreateProduct}>
<ProductsTable></ProductsTable>
</Page>
</Route>
</Switch>
<Switch>
<Route path={`${url}/create`}>
<Dialog show={true} title={'Create product'}
onClose={() => push(url)}><CreateProduct></CreateProduct></Dialog>
</Route>
<Route path={`${url}/:productId/edit`}>
<Dialog show={true} title={'Edit product'} onClose={() => push(url)}><EditProduct></EditProduct></Dialog>
</Route>
</Switch>
</>
);
Upvotes: 8
Reputation: 2487
This should be a start: https://reactrouter.com/web/example/modal-gallery
They conditionally render it as a modal only when you navigate to it from the parent. You can modify it so it always renders as a modal.
Upvotes: -2
Reputation: 633
by changing your first route to
<Route path={`${url}*`}>
<Page title="Products" onCreateButtonClick={gotToCreateProduct}>
<ProductsTable></ProductsTable>
</Page>
</Route>
your component will be displayed for every route that starts with url and by removing the Switch component you will be able to match multiple routes
Upvotes: 0