React routing using components (PageRenderer) - javascript

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.

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>
);
}

Related

Function component on the same page in not picking in route (react-router-dom v6) of react project

I have created a route in my react project using the methods of react-router-dom version 6.2.1.
But when I tried to fetch one route of a functional component written on the same implementation component it is not working.
App.js
import React from 'react';
import './App.css';
import {Routes ,Route} from 'react-router-dom';
import HomePage from './pages/homepage/homepage.component';
const CarsPage= () => {
<div>
<h1>CARS PAGE</h1>
</div>
}
function App() {
return (
<div>
<Routes >
<Route exact path='/' element={<HomePage />} />
<Route exact path='/cars' element={<CarsPage/>} /> // This route is not working.
</Routes>
</div>
);
}
export default App;
Issue
The hats route is not picking up.
Your forgot the return statement in CarsPage
Change it to:
const CarsPage= () => {
return (
<div>
<h1>CARS PAGE</h1>
</div>
)
}
You need to wrap the components in BrowserRouter.
See everything works here: https://codesandbox.io/s/festive-leavitt-7tr1d?file=/src/App.js
Looking at the above implementation, the CarsPage component does not return anything. Refactor it to return your JSX like so.
const CarsPage = () => (
<div>
<h1>CARS PAGE</h1>
</div>
);
Also, import BrowserRouter from "react-router-dom" and wrap the "react-router-dom" component <Routes /> with BrowserRouter as seen in the docs like so
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
...
function App() {
return (
<div>
<Router>
<Routes>
<Route exact path="/" element={<HomePage />} />
<Route exact path="/cars" element={<CarsPage />} />
</Routes>
</Router>
</div>
);
}

React Routing doesnt render

I have tried to learn React and now wanted make a Route but it seems like it doesnt render Overview.
Iam thankful for any help.
import Sidebar from "./components/Sidebar";
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import Overview from "./pages/Overview";
function App() {
return (
<Router>
<Sidebar />
<Switch>
<Route path="/overview" components={Overview} />
</Switch>
</Router>
);
}
export default App;
import React from 'react';
const Overview = () => {
return (
<>
<div>Please Render!!</div>
</>
)
};
export default Overview;
The Route accepts component as param and not components. See here
Your code should be -
import Sidebar from "./components/Sidebar";
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import Overview from "./pages/Overview";
function App() {
return (
<Router>
<Sidebar />
<Switch>
<Route path="/overview" component={Overview} />
</Switch>
</Router>
);
}
export default App;
You have type error, you write components instead of component.
Change this
<Route path="/overview" components={Overview} />
to this
<Route path="/overview" component={Overview} />
Add exact attribute as following:
<Route path="/overview" exact components={Overview} />
You must switch components to component. Just take out the s.

React Where to place login page for a one page app with a side menu

I have a react web app with a sidemenu. Whenever a user clicks on the link in the sidemenu, they are routed to a page that is rendered at the right side of the sidemenu. My question is, how do I do login for such a usecase seeing as any page I route to renders to the right of the sidemenu. I want the login page to be full screen without the side menu showing. This is what App.js looks like.
import React, { Component } from "react";
import { HashRouter } from "react-router-dom";
import Navigation from "./pages/General/components/Navigation";
import SideMenu from "./pages/General/components/SideMenu";
import "../src/css/App.css";
class App extends Component {
render() {
return (
<div>
<HashRouter>
<div className="main-wrapper">
<SideMenu />
<Navigation />
</div>
</HashRouter>
</div>
);
}
}
export default App;
Here is Navigation.js
import React from "react";
import { Route } from "react-router-dom";
import CalendarPage from "../../Calendar/CalendarPage";
import DoctorsList from "../../Doctors/DoctorsList";
import PatientsList from "../../Patients/PatientsList";
import AdminUsersList from "../../AdminUsers/AdminUsersList";
import SpecialitiesList from "../../Specialities/SpecialitiesList";
const Navigation = () => {
return (
<div className="mainarea">
<Route exact path="/" component={CalendarPage} />
<Route exact path="/scheduler" component={CalendarPage} />
<Route exact path="/doctors" component={DoctorsList} />
<Route exact path="/patients" component={PatientsList} />
<Route exact path="/admin-users" component={AdminUsersList} />
<Route exact path="/specialities" component={SpecialitiesList} />
</div>
);
};
export default Navigation;
The best solution I can figure out in terms of a clean design, is to implement another router in your App.jsx, because you are implementing the routing inside your component, and you need another one for your login page.
Then, your App.jsx could be like this:
import React, { Component } from "react";
import { Redirect, Route, Switch } from "react-router-dom";
import LogIn from "./pages/General/components/Login";
import HomePage from "./pages/General/components/HomePage";
import "../src/css/App.css";
class App extends Component {
render() {
return (
<div>
<Switch>
<Route path={'/login'} component={LogIn} />
<Route path={'/'} component={HomePage} />
<Redirect to="/" />
</Switch>
</div>
);
}
}
export default App;
Then, for your HomePage do the following
import React, { Component } from "react";
import { HashRouter } from "react-router-dom";
import Navigation from "./pages/General/components/Navigation";
import SideMenu from "./pages/General/components/SideMenu";
import "../src/css/App.css";
class HomePage extends Component {
render() {
return (
<div>
<HashRouter>
<div className="main-wrapper">
<SideMenu />
<Navigation />
</div>
</HashRouter>
</div>
);
}
}
export default HomePage;
I hope it helps!
Here is my solution, it not exactly a solution, but it will give you a basic idea on how to implement this.
The idea is to place the Login component in app.js, and conditionally display it if the user is logged in.
You will have to pass a handler function to login component through which you will be able to control app.js state.
When login will be sucessfull, u can show the Navigation and Sidemenu component.
import { Fragment } from "react";
import Login from "path/to/login";
class App extends Component {
state = { isLoggedIn: false };
loginHandler = () => {
this.setState({
isLoggedIn: true
});
};
render() {
return (
<div>
<div className="main-wrapper">
{isLoggedIn ? (
<Fragment>
<SideMenu />
<Navigation />
</Fragment>
) : (
<Login loginHandler={this.loginHandler} />
)}
</div>
</div>
);
}
}
Also you need write a separate router file, which will contain the main app.
This is used to show the app component when navigated to /
import React from 'react';
import { HashRouter, Route } from 'react-router-dom';
import App from './app';
const MainRoute = () => (
<HashRouter>
<Route path="/" component={App} />
</HashRouter>
);
export default MainRoute;

MERN: TypeError: undefined is not an object (evaluating 'this.props.params.id')

I am learning MERN using 'Pro MERN Stack' by Vasan Subramanian. The book is good but since there are two years since he wrote it, some of his code no longer work due to changes in the modules he uses. I have a problem recently with one part that I have had to change a lot. It is using react-router and for some reason it stop passing parameters between functions (I am a real beginner, so I probably don't really know what I am talking about). OK, the code is as follows:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, Redirect, Switch } from "react-router-dom";
import PropTypes from 'prop-types';
import IssueList from './IssueList.jsx';
import IssueEdit from './IssueEdit.jsx';
const contentNode = document.getElementById('contents');
const NoMatch = () => <p>Page Not Found</p>;
const App = props => (
<div>
<div className="header">
<h1>Issue Tracker</h1>
</div>
<div className="contents">
{props.children}
</div>
<div className="footer">
Full source code available at this <a href="https://github.com/vasansr/pro-mern-stack">
GitHub repository</a>.
</div>
</div>
);
App.propTypes = {
children: PropTypes.object.isRequired,
};
const RoutedApp = () => (
<App>
<Router>
<Switch>
<Route exact path="/" render={() => <Redirect to="/issues" />} />
<Route exact path="/issues" component={IssueList} />
<Route exact path="/issues/:id" component={IssueEdit} />
<Route path="*" component={NoMatch} />
</Switch>
</Router>
</App>
);
ReactDOM.render(<RoutedApp />, contentNode);
if (module.hot) {
module.hot.accept();
}
IssueList works perfect with that, but IssueEdit doesn't and display an error as in the subject. Here is the code of IssueEdit:
import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
export default class IssueEdit extends React.Component {
// eslint-desable-line
render() {
return (
<div>
<p>This is a placeholder for editing issue {this.props.params.id}.</p>
<Link to="/issues">Back to issue list</Link>
</div>
);
}
}
IssueEdit.propTypes = {
params: PropTypes.object.isRequired,
};
I don't know how to fix it so the {this.props.params.id} will be properly displayed.
Try adding match:
this.props.match.params.id

React Route Redirect

I read all possible thread about programmatically redirection in React but I couldn't make it working.
My code looks like this (I removed as much I could to make it shorter):
import React from 'react';
import {render} from 'react-dom';
import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import {Login} from "./login/Login";
class App extends React.Component {
login(loginResponse) {
...
# Here I want to redirect but it does not work
this.props.history.push('/some-path/');
}
render() {
return (
<Router>
<div>
<div id="content">
<Messages />
<Switch>
<Route path="/" exact={true} component={Welcome} />
...
<Route path="/portal/login" render={() => <Login sendMessage={this.sendMessage} />} />
</Switch>
</div>
</div>
</Router>
);
}
}
render(<App/>, document.getElementById("app"));
I'd like to redirect when the login method is called to a different path.
With this.props.history.push('/some-path/'); I get Cannot read property 'push' of undefined.
In most of the places I read about withRouter but I could not make it work.
What am I missing to get the history?
Or what's the easiest to make the redirect work?
Thanks in advance
I think the main problem here is that I was trying to implement the redirect on the top level component.
I ended up moving a bit of login around and do the redirect from the Login component that is rendered thanks to the Route component therefore can access the history.
This is the code I used:
main.js
import React from 'react';
import {render} from 'react-dom';
import {BrowserRouter as Router, Route, Switch} from "react-router-dom";
import {Login} from "./login/Login";
class App extends React.Component {
render() {
return (
<Router>
<div>
<div id="content">
<Messages />
<Switch>
<Route path="/" exact={true} component={Welcome} />
...
<Route path="/portal/login" render={(router) => <Login router={router} sendMessage={this.sendMessage} />} />
</Switch>
</div>
</div>
</Router>
);
}
}
render(<App/>, document.getElementById("app"));
Login.js
import React from 'react';
export class Login extends React.Component {
constructor(props) {
super(props);
this.onLoginResponse = this.onLoginResponse.bind(this);
}
onLoginResponse(loginResponse) {
...
this.props.router.history.push('/portal/');
}
render() {
return (
<div id="login-form">
Login page ...
</div>
);
}
}
The nice thing of this is that now the code for handling a login response is in the Login page.
But as I wanted to store the user who logged in into the main app status I needed to do some extra work.

Categories

Resources