Hey! I'm on a mission to make 100 React.js projects ending March 8th. Please follow my dev.to profile or my twitter for updates and feel free to reach out if you have questions. Thanks for your support!
Link to today's deployed app: Link
Link to the repo: github
If you're building React applications, you're almost always going to need to build out some routes so that you have an easy way to display separate pages. The standard these days is to use the react-router-dom
npm package.
This project builds on my project from yesterday for a simple blog UI using Ant Design and Lodash. If you want to build this from scratch that's the best place to start.
React Router
React Router is a tool that creates artificial routing to components in your app. Why artificial? Well the url routes are real, but React creates single-page-applications, so the pages themselves are just you telling React "only show this component when the URL is at this address".
In this project I used several parts of the react-router-dom
package, and I had to actually read the (fantastic) docs for it because the tutorial I'm following is quite old and uses a deprecated routing system.
First, you'll need to import the package into your file. I did this in my app component where I display all of the article previews. Here is how you import the package:
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
You'll notice that the import object makes use of aliasing to rename the un-sexy "BrowserRouter" to just "Router".
To use the Router in your application, first open up a JSX element and create the Router component, I filled mine with a switch, which tells React Router to show the component with the first matching path. For this reason, we list our index page at the bottom so it matches last and is thus the default.
const App = () => {
return (
<div className="app_container">
<Router>
<Switch>
<Route path='/post/:id'>
<Post />
</Route>
<Route path='/'>
<Posts />
</Route>
</Switch>
</Router>
</div>
);
}
You can see here that we made use of all three of the components brought in from browser-router-dom
. The Router lets React know that it's a router and to behave accordingly, the Switch tells the Router that it should show the component with the first matching path defined in the path
attribute. The Route elements are where you define the path you want to route to. Child elements are then given to the Route elements to tell the Switch which component you want it to show.
For the index page at path '/', we show the Posts component. This shows a little list of all of the possible cryptocurrencies we have data on like so:
In this component we import the data from our mock api, a JSON file with an array of objects filled with info about cryptocurrencies. We map through each object in the mock api array and display it on the screen using our PostSnippet
component. This was covered in yesterday's project so I won't go over it again, but have a look at the github to check out the JSX for that one. You can also see I set up a navbar using Ant Design's pre-built component that uses a very cool title
attribute.
Displaying the Correct Component
At this point I was at a loss. The tutorial I was following used Reach Router which is sort of old and I believe was folded into the React Router project, so I was on my own. To actually go to the page referenced by the :id
variable in the post path, we need to somehow get that when we're inside the post. How can we do this dynamically? We could pass down props, but what if there are ten thousand cryptos I have articles about?
Enter the React Router useParams()
method. After importing the useParams
object from the react-router-dom
package, in the Post component we can get the actual unique ID used for this page using the method like so:
import {useParams} from 'react-router-dom';
...
const postId = useParams().id;
This searches through the parameters in the actual URL to find one called id
. We can then use this ID to search through our mock cryptocurrency API and find the correct article, without passing that info down from props. I then use the useState
and useEffect
React hooks to set the Post component's state whenever there is a change in that postId variable, so we have content from the API. Here is what that component looks like for me:
import React, {useState,useEffect} from 'react';
import {Card,PageHeader} from 'antd';
import {useParams} from 'react-router-dom';
import api from '../mock_api';
const Post = (props) => {
const postId = useParams().id;
const [title,setTitle] = useState('');
const [content,setContent] = useState('');
const [imageUrl,setImageUrl] = useState('');
useEffect(() => {
let post = api[postId];
setTitle(post.coin);
setContent(post.description);
},[postId])
return (
<div className="post_container">
<div className="page_header_container">
<PageHeader
style={{
border: '1px solid rgb(235,237,240)'
}}
title={title}
/>
</div>
<div className="post_content_container">
<Card style={{marginTop: '20px'}} >
{
content.split('\n').map((textParagraph,idx) => {
return <p key={idx}>{textParagraph}</p>
})
}
</Card>
</div>
</div>
)
}
export default Post;
You can see we also use the Card and PageHeader components from Ant Design here, which I covered in yesterday's tutorial, and a map method to split the description into readable paragraphs whenever there is a pagebreak \n
encoded into the text.
In light of all of this week's hype around certain stocks and crypto, I thought it would be fun to create a little database on the top 5 coindesk cryptocurrencies in their honor.
Look out for dynamic data tomorrow! No more mock APIs!
Top comments (1)
Hey james.
Your challenge is interesting. Keep working on it. Please add these challenge posts as a series so it is easy to access for everyone. thanks