- Read Tutorial
- Watch Guide Video
We are going to make each one of our portfolio boxes here clickable and then we will direct the user to that Portfolio Detail page, and then we're also going to communicate with the API and pull the data in. So, let's get started with that. And along the way, we're also going to learn how you can work with a React application that maybe you didn't create and we're gonna see how we can follow a component path all the way from the top parent component down to the one that you wanna work with, so let's start with that.
If you look at our list of routes here and you scroll all the way down or if you simply search for our PortfolioDetail, you'll see that at the very bottom, we have this route and it's called portfolio/:slug. So, that is where a user can go to and that's where we're going to direct users with our route. So, the very first thing I would do, let's pretend that you just got hired and you are asked to work and you're asked to build out this Portfolio Detail page.
Well, we have to see exactly what we need to do in order to pass data to it and to work with it. So, I'd first open up our portfolio-detail here and you can see it's pretty much just a placeholder functional component. So, that's gonna be the first thing that we can see here, and then we have to see how we can get data in it and we can see how we can direct users to it.
So, let's start off by going to our home page. So, if you go to the home page, you can see that it is simply a div that has a PortfolioContainer in it. Okay, so we know where to start, we start on the home page and now we see this PortfolioContainer component, so let's open up the portfolio-container and if you come here, you can see that it imports PortfolioItem.
So, there is nothing in here directly that gives us the ability to add our link, so we'll keep on following the tree and you can see that we have this PortfolioItem component. So, if we open up portfolio-item, you'll see that this is where we are going to have the ability to add that link.
We have gone all the way from the app to the Portfolio Detail page, and then we saw from the home page and then the container and then the item, we're able to see exactly where we can place the link in.
And whenever I'm taking over a legacy application, that's pretty much the process that I follow and it's one of the really nice things about being able to work with tools like React is that you can follow that kind of process with other languages and frameworks. Such as, say, a Java application, that process is much more challenging. The way they structure their systems is very different than this. And so, this gives us a nice path to follow, so let's go and make each one of these portfolio items clickable.
So, if you look down in the JSX code, you'll see we have our portfolio-item-wrapper, we have our event handlers, and so what we wanna do is make the entire blog clickable. So, if you look at the browser here, I wanna be able to click on CronDose or this DailySmarty or I wanna click on the entire block and be directed to the detail page.
So, let's get started with that, earlier on we imported the Link component, but if you didn't, make sure you import that from react-router-dom. And then we're going to wrap the entire div inside of the Link. So, I'm gonna call the Link component and I'm gonna say that I want this to go to, make sure you use backticks here 'cause we're gonna use string interpolation, I want this to go to /portfolio/ and then we're going to slide in the id.
Now, it's been a while since we worked on this specific component. So, if you remember, we used destructuring here. We pulled out from the prop, we pulled out the id, the description, and all those kinds of things. The id is what we're going to use in the URL. So, we're pulling that out here and so that is gonna give us the URL we're looking for. And then make sure you wrap the entire div, so go all the way down to the bottom and wrap the entire thing with the Link tag, hit save, and now let's go test this out.
portfolio-item.js
render() { const { id, description, thumb_image_url, logo_url } = this.props.item; return ( <Link to={`/portfolio/${id}`}> <div
</div> </div> </Link> ); } }
If you come to the home page and now click on any of your blocks here, now we are directed to the Portfolio Detail page, so this is working very nicely and you can test it out by clicking on different items and you can see that that id is changing, it's dynamic.
So, the next thing we're gonna do now that we have the ability to navigate to that page is, we need to be able to have this Portfolio Detail page call the API, store elements, and then also to run a few processes. Now, that may give you a hint that because we need an event to fire right when this component launches, we are going to have to convert this into a class component.
So right now, it's a functional component, we've gone through this process a few times. It would be good practice if you were to pause the video right now and convert this into a class component, and I want you, if you feel confident enough to do this, I want you to extend it further, and I actually want you to bring the PortfolioItem into the page. I don't care if you render it but at least bring it in so it's in the console.
If you go to devcamp.space and look at the API Endpoints, so you could start off just on the regular home page, and then if you click on Portfolio, you can see the API endpoints.
We want the endpoint that says One Item, so this is gonna be the URL that you're gonna call. And then the only difference is you slide in the id for that specific item for that portfolio item. That's the only difference is when you see this little colon in front of id, that means that is a dynamic id. You need to replace it with whatever yours is.
So, if you feel good and confident about this 'cause we've gone through this a few times, my recommendation is for you to convert this into a class component, call the API, build a function that pulls that data in, that portfolio item data, and have that run as soon as the component is created. So, have fun with that and I'm going to now implement my own solution for this.
So, the first thing that I would do is I'm gonna import the Component module and then I'm going to get rid of everything up top here. And I'm gonna say export default class and this is called PortfolioDetail, and extends Component. And then inside of here, I'll add a constructor, and we do need to pull in props, so I'll pull in the props, call super, and that's all we need to do there.
Then make sure that you call a render statement just like every class component has. And then one last item, a little tricky one here, is if you were calling props.match.params.slug, you now need to call this.props.match.params.slug.
portfolio-detail.js
render() { return ( <div> <h2>Portfolio Deatil for {this.props.match.params.slug}</h2> </div> ); }
So, I'm gonna hit save and now, you can see everything's still working. So, we've successfully converted a functional component into a class component. So now, let's call the API. So, I'm going to create a function here called getPortfolioItem. It's not gonna take in any arguments and I'm going to call axios, which means I need to import it, import axios from axios.
And now, back on line 10 I can say axios.get, and then inside of here, I'm gonna use backticks and let me go grab from devcamp.space this URL. So, I'll grab that API endpoint, paste it in, and then instead of colon id, I'm going to replace that with dollar and then we wanna have this.props. let me see, match, yes, .params.slugs. And then make sure that you end that with a backtick. So, I believe that is everything that we need there.
And let's throw in the withCredentials true flag. That is optional in this case, but I'm gonna do it just to prove to the server who we are. And then at the very end of that, call your then and we want to grab that response. And let's just console.log it, in the next guide, we'll focus on bringing the data in and actually rendering it.
So, I'll say this is our response object and I just want to show the response. And then I wanna catch any errors, so we'll console.log that this is a getPortfolioItem error, and then we'll actually print the error out itself.
portfolio-detail.js
import React, { Component } from "react"; import axios from 'axios'; export default class PortfolioDetail extends Component { constructor(props) { super( props); } getPortfolioItem() { axios .get( `https://jordan.devcamp.space/portfolio/portfolio_items/${ this.props.match.params.slug }`, { withCredentials: true } ) .then(response => { console.log("res", response); }) .catch(error => { console.log("getportfolioitem error", error); }); }
Okay, I'll hit save and I'm going much faster right now than we did earlier in the course because we have implemented this kind of feature quite a few times. So, if this is feeling fuzzy, feel free to pause the video and look at all of that code. We're simply calling the API, we're passing in a dynamic parameter here, so we're passing in that id that we have up in the URL, we're saying we have the withCredentials true flag, and then we're just printing out the response.
Now, from here, I'm going to use a lifecycle hook. So, I'll say componentWillMount and when it does, I want to say this.getPortfolioItem and actually call the function, and hit save.
componentWillMount() {
this.getPortfolioItem();
}
Let's refresh the page and take a look at the console. You can see that we have a res Object, which is what we printed out. And if you look at it, you can click on data here and you can see we clicked on Crondose. So, let's test this out just to make sure it's working with everything else.
So, I'll click on DailySmarty, now we should have another piece of data printed out. And this one, if you click on the data element, it says DailySmarty, so this is working perfectly.
So, great job if you went through that. In the next guide, we're gonna take this data, we are going to add it and update our Portfolio Detail state and we're gonna render it out onto the page.