0

I am working on a News Web Application in React.js, and I am trying to figure out how to route a user to another component's page containing more information about the article they clicked. I've tried a lot of things but I'm pretty lost. I created a hook that fetches the data from a url link with its given data of a news article.

import { useState, useEffect } from 'react';

export const useHttp = (url, dependencies) => {
  const [isLoading, setIsLoading] = useState(false);
  const [fetchedData, setFetchedData] = useState(null);

  useEffect(() => {
      setIsLoading(true);
      console.log('Sending Http request');
      fetch(url)
      .then(res => {
         if (!res.ok) {
             throw new Error('Failed to fetch');
         }
         return res.json();
        
      })
      .then(data => {
        console.log(data);
        setIsLoading(false);
        setFetchedData(data); //something here
      })
      .catch(err => {
        console.log(err);
        setIsLoading(false);
      });
      // eslint-disable-next-line
  }, dependencies);

  return [isLoading, fetchedData];
};

I have several components, with very similar functionality, that use this hook to grab all of the articles from a url particular to that component and maps its data to get values that are later mapped to populate a card component that is called in all of these other components, so that the news articles show on the currently viewed page. Here is a component for science news.

import React from 'react';
import { Spinner, CardDeck } from 'react-bootstrap';
import { CardElement } from './Card';
import { useHttp } from '../hooks/http';

const sciUrl = 'http://newsapi.org/v2/top-headlines?country=us&category=science&apiKey=60d859683c7d4ae68160e82bcc4d39ea';

export const SciNews = () => {
  const [isLoading, fetchedData] = useHttp(sciUrl, []);

  // const classes = useStyles();
  const sciNews = fetchedData
    ? fetchedData.articles.map((article, index) => ({
        image: article.urlToImage,
        name: article.source.name,
        title: article.title,
        description: article.description,
        id: index,
      }))
    : [];

  let content = <Spinner animation="grow" />;

  if (!isLoading && sciNews && sciNews.length > 0) {
    content = (
      <div>
        {sciNews.map((article) => (
          <CardElement key={article.id} article={article} />
        ))}
      </div>
    );
  } else if (!isLoading && (!sciNews || sciNews.length === 0)) {
    content = <p>Could not fetch any data.</p>;
  }
  return content;
};

const sciHomeUrl = 'http://newsapi.org/v2/top-headlines?country=us&category=science&pageSize=3&sortBy=popularity&apiKey=60d859683c7d4ae68160e82bcc4d39ea';

export const SciHomeNews = () => {
  const [isLoading, fetchedData] = useHttp(sciHomeUrl, []);

  // const classes = useStyles();
  const sciHomeNews = fetchedData
    ? fetchedData.articles.map((article, index) => ({
        image: article.urlToImage,
        name: article.source.name,
        title: article.title,
        description: article.description,
        id: index,
      }))
    : [];

  let content = <Spinner animation="grow" />;

  if (!isLoading && sciHomeNews && sciHomeNews.length > 0) {
    content = (
      <CardDeck  style={{paddingLeft: "5%", paddingRight: "5%"}}>
        {sciHomeNews.map((article) => (
          <CardElement key={article.id} article={article} />
        ))}
      </CardDeck>
    );
  } else if (!isLoading && (!sciHomeNews || sciHomeNews.length === 0)) {
    content = <p>Could not fetch any data.</p>;
  }
  return content;
};
  

Here is the Card Component..

import React from 'react';
import { Card, Button } from 'react-bootstrap';

export const CardElement = ({ article }) => (

    <Card
      style={{ height: '75vh' }}
      key={article.id}
      bg="dark"
      text="white"
      className="my-3"
    >
      <Card.Img style={{ height: '50%' }} variant="top" src={article.image} />
      <Card.Body>
        <Card.Text>{article.name}</Card.Text>
        <Card.Title>{article.title}</Card.Title>
        <Card.Text>{article.description}</Card.Text>
        
      </Card.Body>
    </Card>
);

How can I add a button or link to the card component to route the user to a details page, showing only the article clicked? I would like to include the actual content, author, date, etc. on this page of just that 1 article. Thanks

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Mac
  • 35
  • 5
  • Are you using any router? If so, you can create a route with parameter `/science/:id`. In your card component you'd then create a router link with the path `/science/${id}`. In the details page you'd grab that url parameter to fetch that one article with that id. Assuming the api is able handle that. – Shawn Yap Aug 22 '20 at 23:35
  • You can wrap your app in a routing/navigation solution and programmatically push to a route that renders a specific article's details. – Drew Reese Aug 22 '20 at 23:36

0 Answers0