I'm using [email protected] and [email protected]
I have a simple Message Posting demo application to try react-router-dom features, and I couldn't figure how to handle a certain case:
This is my main.jsx:
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import Posts, { loader as postsLoader } from "./routes/Posts";
import NewPost, { action as newPostAction } from "./routes/NewPost";
import RootLayout from "./routes/RootLayout";
import "./index.css";
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
children: [
{
path: "/",
element: <Posts />,
loader: postsLoader,
children: [
{ path: "create-post", element: <NewPost />, action: newPostAction },
],
},
],
},
]);
const rootElement = document.getElementById("root");
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
I'm using [email protected] and [email protected]
I have a simple Message Posting demo application to try react-router-dom features, and I couldn't figure how to handle a certain case:
This is my main.jsx:
import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import Posts, { loader as postsLoader } from "./routes/Posts";
import NewPost, { action as newPostAction } from "./routes/NewPost";
import RootLayout from "./routes/RootLayout";
import "./index.css";
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
children: [
{
path: "/",
element: <Posts />,
loader: postsLoader,
children: [
{ path: "create-post", element: <NewPost />, action: newPostAction },
],
},
],
},
]);
const rootElement = document.getElementById("root");
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
As you see, I'm using a loader function to load the posts to be used with Posts component. Here is Posts.jsx for reference:
import PostsList from "../components/PostsList";
import { Outlet } from "react-router-dom";
function Posts() {
return (
<>
<Outlet />
<main>
<PostsList />
</main>
</>
);
}
export default Posts;
export async function loader() {
const response = await fetch("http://localhost:8080/posts");
const data = await response.json();
return data.posts;
}
And the simple RootLayout.jsx:
import { Outlet } from "react-router-dom";
import MainHeader from "../components/MainHeader";
function RootLayout() {
return (
<>
<MainHeader />
<Outlet />
</>
);
}
export default RootLayout;
And finally, my PostsList.jsx where I use useLoaderData to use that data in rendering posts.
import css from "./PostsList.module.css";
import Post from "./Post";
import { useLoaderData } from "react-router-dom";
function PostsList() {
const posts = useLoaderData();
return posts.length === 0 ? (
<div className={css.noPosts}>
<p>No posts found.</p>
</div>
) : (
<ul className={css.posts}>
{posts.map((post) => (
<Post
key={post.id}
enteredAuthor={post.author}
enteredBody={post.body}
/>
))}
</ul>
);
}
export default PostsList;
The thing is, if I have a slow responding server, I'll have nothing to be displayed on screen. Even though the loader is attached to the Posts, it is the "/" route, thus RootLayout is not rendered as well, so I end up with an empty page (I tried this with adding some delay to the backend to return the response). How can I display a LoadingIndicator component when the data is still not available? Sorry if I couldn't explain my situation well enough. I am a new React learner and I would like to learn to use these new relatively new features well. Many thanks in advance.
Share Improve this question asked 2 days ago KorhanEKorhanE 212 bronze badges 1- I case you missed it, or haven't taken the full tour yet (you earn a badge BTW), there are 100% completely optional actions one can take after someone answers that helps rate and curate content on the site. – Drew Reese Commented 4 hours ago
1 Answer
Reset to default 0You could use the HydrateFallback
or hydrateFallbackElement
prop on the Route
, but note this only works for the initial route page load.
{
path: "/",
element: <Posts />,
loader: postsLoader,
hydrateFallbackElement: <LoadingIndicator />,
children: [
{ path: "create-post", element: <NewPost />, action: newPostAction },
],
},
An alternative would be to forego the route loader and implement the more conventional method of fetching data via a useEffect
hook or using Redux-Toolkit Query or React-Query.