react-router-dom: Functions are not valid as a React child

The react-router-dom warning “Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.” is caused by setting the element property of a <Route> component to the name of the component rather than the tag version of that component. To fix this, ensure you set element to <Component /> instead of Component.

In react-router-dom, you set the component that will render for a particular route by setting the <Route> component’s element property. Unlike some other libraries, however, you do not set that property to the name of the component you want rendered. Rather, you have to set it to the tag version of that component.

Let’s look at an example.

Problem: you set the element property in a Route component to the name of a component rather than an instance of it

Below is an example of some routes that were set up for our react-router-dom tutorial. If you want a more in-depth look at how to use react-router-dom, check out that article.

import { Provider } from "urql";
import { urqlClient } from "./utils";
import { HashRouter, Route, Routes, Link } from "react-router-dom";

import MessagesPage from "./MessagesPage";
import UsersPage from "./UsersPage";

function App() {
    return (
        <Provider value={urqlClient}>
            <HashRouter>
                <div id="menu">
                    Menu: 
                    <Link to="/">Home</Link> 
                    <Link to="/users">Users</Link>
                </div>
                <Routes>
                    <Route path="/" element={MessagesPage} />
                    <Route path="/users" element={UsersPage} />
                </Routes>
            </HashRouter>
        </Provider>
    );
}

export default App;
JavaScript

You’ll notice that we’ve set up two routes, / and /users. However, we’ve made a mistake while doing so:


                <Routes>
                    <Route path="/" element={MessagesPage} />
                    <Route path="/users" element={UsersPage} />
                </Routes>
            </HashRouter>
JavaScript

As you can see above, we accidentally set the element property to the name of the component we want rendered rather than an instance of the component. When we try to run this in our browser, we’ll get a blank space where the component for our route should be, and the following warning in our dev console:

As the error above implies, React components can’t return functions, they have to return other components. This might sound a little confusing at first, and this error doesn’t come right out and say that it has anything to do with react-router-dom. But it can help to think of it this way: when you refer to a component as Component, you’re actually referring to the function that generates that component. When you refer to it as <Component />, though, you’re referring to the result of calling that function, which is an actual instance of that component.

Hopefully that all made sense. Fixing this is pretty simple, so let’s look at the solution next.

Solution: set the element property to an instance of a component

Highlighted below is how we fixed this:

import { Provider } from "urql";
import { urqlClient } from "./utils";
import { HashRouter, Route, Routes, Link } from "react-router-dom";

import MessagesPage from "./MessagesPage";
import UsersPage from "./UsersPage";

function App() {
    return (
        <Provider value={urqlClient}>
            <HashRouter>
                <div id="menu">
                    Menu: 
                    <Link to="/">Home</Link> 
                    <Link to="/users">Users</Link>
                </div>
                <Routes>
                    <Route path="/" element={<MessagesPage />} />
                    <Route path="/users" element={<UsersPage />} />
                </Routes>
            </HashRouter>
        </Provider>
    );
}

export default App;
JavaScript

All you have to do is put your component you want rendered as a tag instead of putting the name of the component as the value of element. Now it should render properly.

Conclusion

In react-router-dom, you have to put an instance of a component as the value of the element property in a <Route> component, otherwise you’ll get the warning “Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it”. It’s an easy mistake to make, since lots of React libraries do want you to pass the name rather than an instance of a component as a property.