javascriptreactjsreact-routerreact-router-dom

Routing using useParams with API


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"


Solution

  • 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".

    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 (
        ...
      );
    };