cdt
cdt

Reputation: 223

React Hooks useEffect Change Fetch URL Call

I'm new to hooks and I have this project (https://thereacttimes.netlify.app/) and it uses the New York Times API to display stories from different news sections.

I created a masthead of section titles. If you click "arts" it will change the URL to https://thereacttimes.netlify.app/arts but I need to use that section title as the fetch URL param and I'm not sure how to re-render/re-fetch with my useEffect Hook. The fetch URL allows us to pass the section like this to fetch different stories: fetch("https://api.nytimes.com/svc/topstories/v2/{section}.json?api-key=4fzCTy6buRI5xtOkZzqo4FfEkzUVAJdr).

If you're asking yourself why its working in production now, its because I hard-coded the URL to work as: fetch("https://api.nytimes.com/svc/topstories/v2/home.json?api-key=4fzCTy6buRI5xtOkZzqo4FfEkzUVAJdr)

What do I change in my useEffect hook? What do I add to the buttons in my masthead component to call the re-render?

News Component

export default function News() {
  const [error, setError] = useState(null);
  const [stories, setStory] = useState(null);

  useEffect(() => {
    fetch(`"https://api.nytimes.com/svc/topstories/v2/{section}.json?api-key=""`)
      .then((res) => res.json())
      .then((data) => {
        setTimeout(() => setStory(data), 1500);
        console.log("Success ", data);
      })
      .catch((error) => {
        console.log("Error", error);
      });
  }, []);

  if (error) {
    return <div>Error: {error.message}</div>;
  } else if (!stories) {
    return <LoadingBar type={"cylon"} color={"#193152"} />;
  } else {
    return (
      <>
        <ul className="stories">
          {stories.results.map((story) => {
            return (
              <Story
                title={story.title}
                abstract={story.abstract}
                img={story.multimedia[0].url}
                alt={story.multimedia[0].caption}
                link={story.url}
              />
            );
          })}
        </ul>
        <Spacer height={100} />
      </>
    );
  }
}

Masthead Component

import React from "react";
import uuid from "uuid";

var sections = [
  "arts",
  "business",
  "fashion",
  "health",
  "movies",
  "opinion",
  "politics",
  "science",
  "sports",
  "technology",
];

export default function Masthead() {
  return (
    <div className="masthead">
      {sections.map((section) => {
        return (
          <a href={section} key={uuid}>
            <span>{section}</span>
          </a>
        );
      })}
    </div>
  );
}

Upvotes: 2

Views: 2914

Answers (2)

SuleymanSah
SuleymanSah

Reputation: 17888

To be able to rerender the News component when the section changes, you need to add section to the dependency list in the useeffect like [section].

By the way there is no section variable in the News component, I guess what you are trying to do is pass a section parameter to the News component, if so you had better to use routing, and pass the section parameter to the News component.

Here is a working codesandbox with some other changes and refactoring:

Upvotes: 3

codemonkey
codemonkey

Reputation: 7915

I would need to understand the larger context of your app of course to come up with a more elegant solution, but just a cursory look at what you have provided suggests using something as simple as this:

const getCurrentPage = () => {
  const url = new URL(window.location.href);
  const page = url.pathname.split('/').pop();
  return page ? page: 'home';
}

export default function News() {
  const [error, setError] = useState(null);
  const [stories, setStory] = useState(null);

  useEffect(() => {
    const section = getCurrentPage();
    fetch(`https://api.nytimes.com/svc/topstories/v2/${section}.json?api-key=4fzCTy6buRI5xtOkZzqo4FfEkzUVAJdr`)
      .then((res) => res.json())
      .then((data) => {
        setTimeout(() => setStory(data), 1500);
        console.log("Success ", data);
      })
      .catch((error) => {
        console.log("Error", error);
      });
  }, []);
...
...

Nice touch on The React Times by the way.

Upvotes: 2

Related Questions