
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeThe 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:
*[_type == "post" && slug.current == $slug][0] filters documents by type and slug, using parameters for safe value passing[0] at the end returns only the first match (or null if no match exists)null, you know the document doesn't exist<Navigate> component to redirect to your NotFound route when the post doesn't exist* route will catch any other unmatched routesThis 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.
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store