0

I'm refactoring my React app to Typescript. I added types for the child component, but now that I'm working on the Parent component, I'm lost as to how to type this.

I fetch data from an endpoint and pass it down to Recommendations along with the boolean value of loading. How do I add types for the Parent here and what do I need to change when passing here: <Recommendations title={"Trending"} data={trending} loading={isLoading} />?

Also, my app compiles correctly, but did I do this correctly in child component?

App Component (Parent)

const App = (): ReactElement => {
  const [trending, setTrending] = useState([]);
  const [isLoading, setIsLoading] = useState<boolean>(false);

  useEffect(() => {
    const fetchTrending = async () => {
      setIsLoading(true);

      const res = await fetch(
        `https://api.themoviedb.org/3/trending/movie/day?api_key=${API_KEY}`
      );
      const data = await res.json();
      const results = data.results;

      setTrending(results);
      setIsLoading(false);
    };

    fetchTrending();
  }, [API_KEY]);

  return (
    <div className="App">
      <Recommendations title={"Trending"} data={trending} loading={isLoading} />
    </div>
  );
};

export default App;

Recommendations Component (Child)


interface IRecommendationData {
  data: Array<IRecommendations>;
  loading: boolean;
  title: string;
}

interface IRecommendations {
  title: string;
  id: string;
  poster_path: string;
}

const Recommendations = ({title, data, loading}: IRecommendationData): ReactElement => {
  
  return (
    <div className="recommendationSection">
      <h3>{title}</h3>

      {loading ? (
        <h3>Loading...</h3>
      ) : (
        <Slider {...settings}>
          {data.map((movie) => {
            return (
              <Link
                to={{
                  pathname: `/movie/${movie.id}`,
                  state: { ...movie },
                }}
                key={movie.title}
              >
                <div className="banner recBanner">
                  <img
                    src={
                      movie.poster_path
                        ? `https://image.tmdb.org/t/p/original/${movie.poster_path}`
                        : "https://www.genius100visions.com/wp-content/uploads/2017/09/placeholder-vertical.jpg"
                    }
                    alt={movie.title}
                  />
                </div>
              </Link>
            );
          })}
        </Slider>
      )}
    </div>
  );
};

export default Recommendations;

--- EDIT ---

App Component (Parent)

In the parent I took that second interface from the child and then exported it, as per this post, as an array of interfaces.

interface IRecommendations {
  title: string;
  id: string;
  poster_path: string;
}

export type RecommendationData = IRecommendations[];

const [trending, setTrending] = useState<IRecommendations[]>([]);

Recommendations Component (Child)

Then I set the data to said imported interface and set the props type to that.

import { RecommendationData } from "../../pages/Home";

interface IRecommendationData {
  data: RecommendationData;
  loading: boolean;
  title: string;
}

const Recommendations = ({title, data, loading}: RecommendationData): ReactElement => {
cdt
  • 193
  • 1
  • 2
  • 17
  • your code seems pretty good. Only thing is, since `data` is of type `Array`, you should type the `useState` hook that way too: `const [trending, setTrending] = useState>([])` – Bao Huynh Lam Jun 30 '21 at 19:45
  • thanks @BaoHuynhLam, but the types are declared in the child component. Do I move one/both of them up to the parent and somehow pass them down? I can't just write `const [trending, setTrending] = useState>([])` because that's in the parent and I currently have no types set there. That's where I'm confused. I did things backwards by adding types to the child first and now I'm trying to figure out how to do this correctly. – cdt Jul 01 '21 at 13:18
  • 1
    The data is fetched in the parent, so parent should be the one that knows and controls the data interfaces. Move the interface declarations to the parent file, and export them so the child file could import and use. – Bao Huynh Lam Jul 01 '21 at 14:26
  • hey @BaoHuynhLam, yeah i just edited my post with some changes. can you let me know how this looks? i think thats what i did from my research. – cdt Jul 01 '21 at 14:28
  • 1
    Looks good but there is a typo. The props type for child component should be `IRecommendationData`, not `RecommendationData`: `const Recommendations = ({title, data, loading}: IRecommendationData): ReactElement =>`. I usually opt for a interface naming schemes like this: Props interface = Component name + "Props" (i.e `RecommendationsProps` instead of `IRecommendationData`), and I would remove the "I" from interface names - `SingleRecommendation` instead of `IRecommendations`. So yeah, beware of your own naming schemes to not get things mixed up – Bao Huynh Lam Jul 01 '21 at 14:36
  • thanks @BaoHuynhLam! Yeah, I just made a typo here in SO. I had in correct in my app, but you're right about the naming convention. That makes more sense. In my learnings, I saw a lot of folks opt for "I"+name for it so I just followed suit. I just want to know what 2021's "best practices" are and follow them but its hard with so much info out there from different years. – cdt Jul 01 '21 at 15:20
  • Not really best practices, just personal preference. You may like to use "I" and it's fine. "I" or not, if the main content/main name remains descriptive, it is still good. Just create a convention of your own and stick with it. By the way, if you have solved the question, consider writing an answer for others with similar problem can see – Bao Huynh Lam Jul 01 '21 at 15:22

0 Answers0