DEV Community

KeithArogo
KeithArogo

Posted on

Dynamic Pages using React Router v6.3

Dynamic pages and routes can be defined as pages that contain content relevant to them. An example of this could be a user’s profile page on a social media website. Social media platforms more often than not contain profile pages that display a user’s general information. Different users will have different information on their profiles but the overall structure stays the same, that is the essence of dynamic pages.

Let's see how we can implement this in React. We'll be using the Ghibli API to get a list of films and we'll implement dynamic pages and routes for all of them. Clicking on the film will then take you to a dynamic page that displays more information about the said film.

Step 1

Create a new React project using create-react-app. Also install React Router by running ‘npm install react-router-dom’ in your project folder via terminal. The react-router-dom package contains bindings for using React Router in web applications

Open the App.js file and remove the default code and add the following;

import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import MoviePage from "./MoviePage";
import HomePage from "./HomePage";

const App = () => {
  return (
    <div>
      <Router>
        <Routes>
          <Route exact path="/" element={<HomePage />} />
          <Route path="/movie/:movieId" element={<MoviePage />} />
        </Routes>
      </Router>
    </div>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

Step 2

create another separate component called Homepage. This will be our homepage from where we'll call the Ghibli API to get film data. We've already defined a route for this component in App.js. Now let's go ahead and add in the API call.

import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";


const HomePage = () => {
    const [isLoading, setIsLoading] = useState(true);
    const [data, setData] = useState();

    useEffect(() => {
      fetch("https://ghibliapi.herokuapp.com/films", {})
        .then((res) => res.json())
        .then((response) => {
          setData(response);
          setIsLoading(false);
        })
        .catch((error) => console.log(error));
    }, []);

    console.log("Data!", data);

    return (
      <>
        {!isLoading &&
          data.map((movie) => {
            return (
              <h5 key={movie.id}>
                <Link to={`/movie/${movie.id}`}>{movie.title}'s Page</Link>
              </h5>
            );
          })}
      </>
    );
  };

  export default HomePage;

Enter fullscreen mode Exit fullscreen mode

We have two states, isLoading which could either be true or false should tell us whether we have received the data from the API or not.

We use a useEffect hook to fetch data when the HomePage component renders. When we obtain the data from the API we set the value of isLoading to false and data to whatever JSON we get.

Now, if you look at the jsx inside the HomePage component you'll see that we check the value of isLoading and if it's false, we map through the response data to render the names of the films.

Run your app with ‘npm start’ and you should see the film names on display.

Step 3

But, we don't just want a list of movies, we also want separate pages with dynamic routes for each of them.

So let's create another component called MoviePage which will fetch data from an API getting the details of each movie.

import React, { useState, useEffect } from "react";
import { Link, useParams } from "react-router-dom";

const MoviePage = () => {
  const { movieId } = useParams();
  const [isLoading, setIsLoading] = useState(true);
  const [data, setData] = useState();

  useEffect(() => {
    fetch(`https://ghibliapi.herokuapp.com/films/${movieId}`, {})
      .then((res) => res.json())
      .then((response) => {
        setData(response);
        setIsLoading(false);
        console.log(`https://ghibliapi.herokuapp.com/films/${movieId}`);
      })
      .catch((error) => console.log(error));
  }, [movieId]);
  console.log(data);

  return (
    <>
      {!isLoading && (
        <>
          <h1>Title: {data.title}</h1>
          <h2>Plot: {data.description}</h2>
          <Link to="/">Back to homepage</Link>
        </>
      )}
    </>
  );
};

export default MoviePage;

Enter fullscreen mode Exit fullscreen mode

We have defined a MoviePage component which lists details about each person by getting data from the API in the same fashion as HomePage. We have also defined a new route for this component i.e, movie/:movieId. This is a bit different compared to our regular routes. Here we pass a parameter movieId through the route. That way a single component at that route can be dynamic based on that parameter.

HomePage returns links to this dynamic route with the movie id as the route parameter.

If you observe MoviePage closely, you'll realize that while the structure of it stays the same, all the content on the page is dependent on movieId i.e, the component is fully dynamic.

The useParams hook returns an object of key/value pairs of the dynamic params from the current URL that were matched by the . Child routes inherit all params from their parent routes. useParams hook lets you access the parameters of the current route.

Conclusion

If you'd like to gain more insight into React Router, read the official docs,

React Router Docs

Buy Me A Coffee

Top comments (0)