While working on a project I needed to get some information out of the URL in the browser. Using the URL to declare what to display is a common situation for frontend, client-side rendering. For example, grabbing an ID or username to send to the backend which is the situation for my current project.
I was using class-based React components when I began learning React. Six months later I'm learning the ins and outs of functional components with Hooks to maintain necessary stateful logic without all the extra lifecycle methods. This learning led me to discover the Hooks of React Router.
<Route path={'/quizzes/:id'} render={props => <Quiz {...props}} />
class Quiz extends Component {
this.state = {
//necessary state values here
}
componentDidMount {
api.getQuiz(props.match.params.id).then(data =>
// logic
)
}
Here's a code snippet from a project I worked on when I first started with React. This Route Path
component has parameters that I want to use. While using the render method of Route, I have to destructure or "spread" props inside the component to gain access to the match object.
I declare that anything following the /quizzes/
portion of the Route will be an :id
. I pass props into the callback and spread the props object into the Quiz component as outlined by the React Router documentation. All this to gain access to the piece of the URL I need. Now when the user is at myapp.com/quizzes/1
a Quiz component will be rendered. Once this component mounts it will use the 1 from the URL as an ID and make a call to my backend to filter through my Quiz database. If the URL were myapp.com/quizzes/cat
then my API call would try using cat
as an ID and an error would be sent back from my database. Unless of course, my database contains a quiz with the ID of cat
.
It's worth noting when I wrote the first project I was very new to React and I had been instructed to use the render method to gain access to props. Looking back, I may have been able to make this code less tedious by using the component method of Route where the components already have access to match, history & history
as you'll see me do in the next example.
Here is what that same functionality looks like with the useParams() hook.
<Route exact path="/seasons/:id" component={Season} />
const Team = () => {
const [state, setState] = useState({});
const { id }= useParams();
useEffect(() => {
api.getTeam(id).then(data => {
//logic
}
};
Once again I declare anything following /seasons/
will be an :id
. Gaining access to the params
is as simple as calling the hook and destructuring the match object, which I know will have a key of id
, which points to my value (ie 1
or cat
). I don't have to chain calls like in the last example props.match.params.id
.
I'm still learning about all the benefits of hooks but I do prefer the look of the code. Thanks for reading, and I'm happy to share my limited knowledge if you have any questions. I'm also very interested in feedback on my use cases.
Update: I've been recently working in typescript. I'm revisiting this article to add how to use this hook with TS. This is assuming you have some basic understanding of Typescript. If you don't, I'd recommend this very basic guide : Typescript for Beginner Programmers by ChibiCode.
In order to useParams
you need to implement a generic for useParams. Building on my example above, I need to type the id
.
type QuizParams = {
id: string;
};
// In order to implement that, I'd apply my type to the hook when calling it.
const { id } = useParams<QuizParams>();
Now typescript knows what to expect as a return value from the useParams
hook.
Top comments (7)
Thank you for the article, the typescript part helps a lot.
Thank you.
why it doesnt work with interface?
Thanks for this!
why it doesnt work with interface?
Great article.
Thank you.