DEV Community

loading...
Cover image for React Router: How to Render Routes Without a Link Component

React Router: How to Render Routes Without a Link Component

kirstybrews profile image Kirsty Brewster Updated on ・3 min read

While creating my most recent project, I came across a situation in how I wanted to use React Router. React Router provides the options to easily create links that link to a specific component and also render a URL defined by the coder. However, what if you don't always want to use links? My partner and I thought it would be cool to have a card in our RecipeContainer that, when clicked, would take a user to the NewRecipeForm.

new recipe without using history

So how to get our component to link to our NewRecipeForm route?

After some time of research, I found out that we could use an object called 'history' to render our specific route upon a certain action (i.e. clicking on a card component). There were two different ways to do this, depending on if our component was a function or a class. I had built this particular component as a function, and so I implemented a hook called 'useHistory'. This hook allowed me to push a URL into the history object, so that upon a certain action, I would be taken to that URL.

AddRecipeCard component

clicking on card now leads to /NewRecipeForm route

Voila! It worked! Surprisingly easily. Now we can do the same thing in a class component. Let's say that I want the recipes page to render once my EditRecipeForm (a class component) is submitted. I can create a function called 'renderRecipes' which uses history.push to render the recipes URL. I can then call this function after my form has been submitted.

renderRecipes function

calling renderRecipes after editing a recipe

example of rendering recipes on frontend

Great! Using history works in a class component too! However, I ran into some trouble when I tried the same thing in our RecipeModal, which was also a class component.

history.push error

Each RecipeModal had an edit button and a delete button. I wanted the edit button to link to a route for the EditRecipeForm, but I kept getting the error, "Cannot read property 'push' of undefined". Basically saying, there is no history object. But why?

The solution was surprisingly and frustratingly simple.

BrowserRouter has its own history object, so any component rendered within this router has access to that history object as long as we pass it down as props. This was the case for our RecipeContainer, as you can see when we view props for RecipeContainer using Dev Tools.

importing BrowserRouter

passing router props to RecipeContainer

viewing history prop in RecipeContainer

However, if we look at our props for our RecipeComponent and RecipeModal, we can see that there is no history object. It didn't get passed down from the RecipeContainer to the RecipeModal.

no history prop in RecipeComponent or RecipeModal

I didn't figure this out in time before our project was due, so I just ended up changing our RecipeModal from a class component to a functional component and using the 'useHistory' hook again; however, if I had passed down that history object to the RecipeModal, my previous attempt would've worked just fine.

Passing history prop from RecipeContainer to RecipeComponent
Passing history prop from RecipeComponent to RecipeModal

Passing history prop from RecipeComponent to RecipeModal

Using history.push in RecipeModal

Rendering EditRecipeForm on frontend

Success! :)

Now I understand history in React Router just a little bit better and I hope anyone reading does too!

Discussion (0)

pic
Editor guide