React routing using components (PageRenderer)

Viewed 131

I'm trying to do basic routing in React. Usually what I have done, and what I will mention later on, is use element={<some page>}. But currently I want to learn and experiment what other options there are, so I came across components where you insert a function. I have followed a tutorial and I did the exact same, except the tutorial uses an older version of router dom so it doesn't use Routes.

Here is the code:

App.js:

import {BrowserRouter as Router, Routes, Route} from 'react-router-dom'

import Register from './pages/register';
import Login from './pages/login';
import PageRender from './PageRender';

function App() {
  return (
    <Router>
      <input type='checkbox' id='theme'/>
      <div className="App">
        <div className="main"> 
        <Routes> 
          <Route exact path="/:page" component={PageRender}/>
          <Route exact path="/:page/:id" component={PageRender}/>
        </Routes>
        </div>
      </div>
    </Router>
  );
}

export default App;

PageRender.js:

import React from 'react'
import { useParams } from 'react-router'
import NotFound from './components/NotFound'

const generatePage = (pageName) => {
    const component = () => require(`./pages/${pageName}`).default

    try {
        return React.createElement(component())
    } catch (err) {
        return <NotFound />
    }
}


const PageRender = () => {
    const {page, id} = useParams()
    let pageName = "";

    if(id){
        pageName = `${page}/[id]`
    }else{
        pageName = `${page}`
    }

    return generatePage(pageName)
}

export default PageRender

The login and register js are just basic arrow functions which display login or register (still didn't come to that part). What I want to do is when I enter the url, let's say for instance: http://localhost:3000/register, it sends me to register page and if I enter a wrong path it will send me to the "NotFound" page. But sadly, it doesn't work. I know I can work around this problem if I simply do this:

<Route exact path="/login" element={<Login/>}/>

This method works, but currently I'm in the process of learning and I'm curious why this method didn't work.

1 Answers

I was able to get your code working in react-router-dom v5, the trick was importing the components once in App so they are built/transpiled. The PageRender component worked as-is.

RRDv5

import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";

import './pages/register';
import "./pages/login";
import PageRender from "./PageRender";

export default function App() {
  return (
    <Router>
      <input type="checkbox" id="theme" />
      <div className="App">
        <div className="main">
          <Switch>
            <Route path="/:page/:id" component={PageRender} />
            <Route path="/:page" component={PageRender} />
          </Switch>
        </div>
      </div>
    </Router>
  );
}

RRDv6 - Swap the Switch component to the Routes component, and switch to using the element prop instead of the component prop to render the PageRender component as JSX.

import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";

import './pages/register';
import "./pages/login";
import PageRender from "./PageRender";

export default function App() {
  return (
    <Router>
      <input type="checkbox" id="theme" />
      <div className="App">
        <div className="main">
          <Routes>
            <Route path="/:page/:id" element={<PageRender />} />
            <Route path="/:page" element={<PageRender />} />
          </Routes>
        </div>
      </div>
    </Router>
  );
}

Edit react-routing-using-components-pagerenderer

Related