I need to route to Tags page while the route URL will be "/category"
, so the display of all news category clicked will be displayed on the tags.jsx
page.
app.jsx
import './App.css'
import Navbar from '../src/Navbar'
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Home from './Pages/Home';
import Health from './Pages/Health';
import News from './Pages/News';
import Tags from './Pages/Tags';
import Profile from './Pages/Profile';
function App() {
return (
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/health" element={<Health />} />
<Route path="/news" element={<News />} />
<Route path="/category/:categoryName" element={<Tags />} />
</Routes>
</Router>
)
}
export default App
Component fetching the news from an API
Headlines.jsx
import React, { useState, useEffect } from 'react';
import PostContent from './postContent';
import PostFooter from './postFooter';
import PostHeader from './postHeader';
import { useParams } from 'react-router-dom';
const Headlines = () => {
const { categoryName }= useParams();
const [update, setUpdate] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const apiUrl = 'https://newsdata.io/api/1/sources?apikey=XYZ';
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error(`HTTP error!: ${response.status}`);
}
const result = await response.json();
setUpdate(result.results);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) {
return <div>Loading news headlines...</div>;
}
if (error) {
return <div>Error fetching news headlines: {error}</div>;
}
return (
<div>
{update.map((item) => (
<div key={item.id}>
<PostHeader
postName={item.name}
imageIcon={item.icon}
/>
<PostContent postDescription={item.description} postUrl={item.url} />
<PostFooter postCategory={item.category} postLanguage={item.language} postCountry={item.country} />
</div>
))}
</div>
);
};
export default Headlines;
Tags.jsx meant to display all news under the category clicked upon
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
const Tags = () => {
const { categoryName } = useParams();
const [display, setDisplay] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchArticles = async () => {
setLoading(true);
try {
const response = await fetch(`https://newsdata.io/api/1/sources?apikey=XYZ?${categoryName}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setDisplay(result.articles);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};
fetchArticles();
}, [categoryName]);
if (loading) {
return <div>Loading articles for {categoryName}...</div>;
}
if (error) {
return <div>Error fetching articles: {error}</div>;
}
return (
<div>
<h1>Articles in Category: {categoryName}</h1>
<div className="article-list">
{display.map((article, index) => (
<div key={index} className="article-item">
<h3>{article.title}</h3>
<p>{article.description}</p>
<a href={article.url} target="_blank" rel="noopener noreferrer">
Read more
</a>
</div>
))}
</div>
</div>
);
};
export default Tags
Navbar.jsx
import React from 'react';
import { Link } from 'react-router-dom';
import './Css/Navbar.css'
const Navbar = () => {
return (
<nav>
<ul>
<li>
<Link to='/'>Home</Link>
</li>
<li>
<Link to="/news">News</Link>
</li>
<li>
<Link to='/health'>Health</Link>
</li>
<li>
<Link to='/category'>Tags</Link>
</li>
<li>
<Link to='/profile'>Profile</Link>
</li>
</ul>
</nav>
);
}
export default Navbar;
What I tried this but on my console it is saying
no routes matched location "/category"
my console its saying 'no routes matched location "/category"'
If you are navigating to "/category"
then this is accurate. There are a couple options to render/match "/category"
.
Render an explicit route to match:
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/health" element={<Health />} />
<Route path="/news" element={<News />} />
<Route path="/category" element={<Tags />} />
<Route path="/category/:categoryName" element={<Tags />} />
</Routes>
</Router>
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/health" element={<Health />} />
<Route path="/news" element={<News />} />
<Route path="/category">
<Route index element={<Tags />} />
<Route path=":categoryName" element={<Tags />} />
</Route>
</Routes>
</Router>
Make the categoryName
segment optional. This was introduced a bit later in v6, version 6.8 if I can recall correctly:
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/health" element={<Health />} />
<Route path="/news" element={<News />} />
<Route path="/category/:categoryName?" element={<Tags />} />
</Routes>
</Router>
The Tags
component should be rendered when its route matches both "/category"
and "/category:categoryName"
.
Now that Tags
is rendered where the categoryName
route path parameter is possibly undefined you should update Tags
to handle this and not make malformed API requests if it matters to the backend endpoint.
Example:
const Tags = () => {
const { categoryName } = useParams();
const [display, setDisplay] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchArticles = async (categoryName) => {
setLoading(true);
try {
const response = await fetch(`https://newsdata.io/api/1/sources?apikey=XYZ?${categoryName}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setDisplay(result.articles);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};
if (categoryName) {
fetchArticles(categoryName);
}
}, [categoryName]);
...
return (
...
);
};