Check if Sanity post exists in React Router v5/v6 before rendering
The issue you're experiencing is that your BlogSinglePost component needs to check if the document exists and handle the case when it doesn't. React Router will always match the /blog/:slug route before the * wildcard route, so you need to handle the 404 logic inside your BlogSinglePost component itself.
Here's how to fix this:
In your BlogSinglePost component:
import { useParams, Navigate } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { client } from './sanityClient'; // your Sanity client
const BlogSinglePost = () => {
const { slug } = useParams();
const [post, setPost] = useState(null);
const [loading, setLoading] = useState(true);
const [notFound, setNotFound] = useState(false);
useEffect(() => {
const query = `*[_type == "post" && slug.current == $slug][0]`;
client.fetch(query, { slug })
.then((data) => {
if (!data) {
setNotFound(true);
} else {
setPost(data);
}
setLoading(false);
})
.catch((error) => {
console.error('Error fetching post:', error);
setNotFound(true);
setLoading(false);
});
}, [slug]);
if (loading) return <div>Loading...</div>;
if (notFound) return <Navigate to="/404" replace />;
return (
<div>
{/* Your post content */}
<h1>{post.title}</h1>
{/* ... */}
</div>
);
};Update your routes:
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route element={<AllPosts />} path="/" exact />
<Route element={<BlogSinglePost />} path="/blog/:slug" />
<Route element={<NotFound />} path="/404" />
<Route element={<NotFound />} path="*" />
</Routes>
</BrowserRouter>
);
};Key points:
- The GROQ query with parameters
*[_type == "post" && slug.current == $slug][0]filters documents by type and slug, using parameters for safe value passing - The
[0]at the end returns only the first match (ornullif no match exists) - When client.fetch returns
null, you know the document doesn't exist - Use React Router's
<Navigate>component to redirect to your NotFound route when the post doesn't exist - The wildcard
*route will catch any other unmatched routes
This approach ensures that the document existence check happens at the data-fetching level, which is where it needs to be since React Router doesn't know anything about your Sanity content.
Show original thread7 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.