DEV Community

Cover image for Get Data using Dynamic Routes in React
Francisco Mendes
Francisco Mendes

Posted on

Get Data using Dynamic Routes in React

One of the most common needs we all have is consuming data in the frontend dynamically and one of the solutions is the use of parameters in our routes.

If you already have some experience with the backend, whether it is creating an Api or consuming an Api through the frontend, we are constantly doing something like this:

/api/v1/posts/10
Enter fullscreen mode Exit fullscreen mode

Which actually corresponds to this:

/api/v1/posts/:id
Enter fullscreen mode Exit fullscreen mode

And by using the react router dom's useParams() hook, we have access to the route parameters of our applications.

So the idea of today's example is to have a list of posts on the main page and when we click on one of them we go to a dynamic page that will only show the post that was selected.

Let's code

First we have to install the following dependencies:

npm i react-router-dom axios
Enter fullscreen mode Exit fullscreen mode

Then in our App.jsx we will define all our routes.

// @src/App.jsx

import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

import Home from "./pages/Home";
import Post from "./pages/Post";

const App = () => {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/post/:id" component={Post} />
      </Switch>
    </Router>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

In the previous code, in the post route, we added a parameter called id that will later be used to fetch the post in question. And now we have to create each of our pages.

// @src/pages/Home.jsx

import React from "react";

const Home = () => {
  return <h1>Home</h1>
};

export default Home;
Enter fullscreen mode Exit fullscreen mode

First let's deal with the state of our component, for that we'll use the useState() hook. And we already have in mind that we are going to have a list of posts so the state will be an array.

// @src/pages/Home.jsx

import React, { useState } from "react";

const Home = () => {
  const [posts, setPosts] = useState([]);
  return <h1>Home</h1>
};

export default Home;
Enter fullscreen mode Exit fullscreen mode

Now we have to fetch the data as soon as the component is rendered, for that we will use useEffect() and we will consume the jsonplaceholder Api using axios.

// @src/pages/Home.jsx

import React, { useEffect, useState } from "react";
import axios from "axios";

const Home = () => {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    const fetch = async () => {
      try {
        const { data } = await axios.get("https://jsonplaceholder.typicode.com/posts");
        setPosts(data);
      } catch (err) {
        console.error(err);
      }
    };
    fetch();
  }, []);
  return <h1>Home</h1>
};

export default Home;
Enter fullscreen mode Exit fullscreen mode

Now we can list our posts in the template but first we have to import the Link component from the react router dom. Like this:

// @src/pages/Home.jsx

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

const Home = () => {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    const fetch = async () => {
      try {
        const { data } = await axios.get("https://jsonplaceholder.typicode.com/posts");
        setPosts(data);
      } catch (err) {
        console.error(err);
      }
    };
    fetch();
  }, []);
  return (
    <>
      {posts.map((el) => (
        <article key={el.id}>
          <Link>
            <h1>{el.title}</h1>
          </Link>
          <p>{el.body}</p>
        </article>
      ))}
    </>
  );
};

export default Home;
Enter fullscreen mode Exit fullscreen mode

Now, in order to dynamically pass the id of the element that is clicked, we have to do it like this:

// @src/pages/Home.jsx

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

const Home = () => {
  // Hidden for simplicity
  return (
    <>
      {posts.map((el) => (
        <article key={el.id}>
          <Link to={`/post/${el.id}`}>
            <h1>{el.title}</h1>
          </Link>
          <p>{el.body}</p>
        </article>
      ))}
    </>
  );
};

export default Home;
Enter fullscreen mode Exit fullscreen mode

And you should get a result similar to this:

post list

Now we can start working on the Post.jsx page.

// @src/pages/Post.jsx

import React from "react";

const Post = () => {
  return <h1>Single Post</h1>
};

export default Post;
Enter fullscreen mode Exit fullscreen mode

Let's start again by working on the component's state and in this case we know that it will have to be an object as it will only be a post.

// @src/pages/Post.jsx

import React, { useState } from "react";

const Post = () => {
  const [post, SetPost] = useState({});
  return <h1>Single Post</h1>
};

export default Post;
Enter fullscreen mode Exit fullscreen mode

Then we'll import the useParams() hook from the react router dom and get the id.

// @src/pages/Post.jsx

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

const Post = () => {
  const { id } = useParams();
  const [post, SetPost] = useState({});
  return <h1>Single Post</h1>
};

export default Post;
Enter fullscreen mode Exit fullscreen mode

Now we can use the useEffect() hook to fetch the post data as soon as the component is rendered. But this time we're going to pass the id that we got dynamically to get that specific post.

// @src/pages/Post.jsx

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

const Post = () => {
  const { id } = useParams();
  const [post, SetPost] = useState({});
  useEffect(() => {
    const fetch = async () => {
      try {
        const { data } = await axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`);
        SetPost(data);
      } catch (err) {
        console.error(err);
      }
    };
    fetch();
  }, []);
  return <h1>Single Post</h1>
};

export default Post;
Enter fullscreen mode Exit fullscreen mode

Now we can start working on our component template.

// @src/pages/Post.jsx

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

const Post = () => {
  const { id } = useParams();
  const [post, SetPost] = useState({});
  useEffect(() => {
    const fetch = async () => {
      try {
        const { data } = await axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`);
        SetPost(data);
      } catch (err) {
        console.error(err);
      }
    };
    fetch();
  }, []);
  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <br />
      <button>Go back</button>
    </article>
  );
};

export default Post;
Enter fullscreen mode Exit fullscreen mode

Last but not least, let's use the useHistory() hook to push the user to the main page.

// @src/pages/Post.jsx

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

const Post = () => {
  const { id } = useParams();
  const { push } = useHistory();
  const [post, SetPost] = useState({});
  useEffect(() => {
    const fetch = async () => {
      try {
        const { data } = await axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`);
        SetPost(data);
      } catch (err) {
        console.error(err);
      }
    };
    fetch();
  }, []);
  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <br />
      <button onClick={() => push("/")}>Go back</button>
    </article>
  );
};

export default Post;
Enter fullscreen mode Exit fullscreen mode

The final result of the application should look like the following:

reads single post

Conclusion

As always, I hope it was clear and that this article has helped you.

Have a great day! 🪗 😁

Oldest comments (5)

Collapse
 
ash_bergs profile image
Ash

Great post, thanks for writing. A succinct review of passing and working with dynamic props!

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Thank you very much for your comment. 😊

Collapse
 
lamorbidamacchina profile image
Simone

Very clear and well written post. Thank you.
Just a quick fix, when I tried the code I had to import axios on the Post.jsx to make it work.

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Thank you very much! 🙌 I forgot to paste axios 😅

Collapse
 
adeyemiadekunle profile image
Adeyemi Adekunle

Nice work and well written, this was a life saver. Thanks