I have recently started developing frontend apps with React and I come from a little programming experience with react-native.
To improve my knowledge on react I studied both the official documentation and took courses on udemy.
So I'm building a small test app in which to use react routing (following what we saw in the udemy course).
However, I have the following error related to routing (I attach the error screen)
I have searched here on the stack that online for possible solutions, such as downgrading react-router-dom, or modifying the history declaration, but unfortunately I still get this error and I can't understand what it comes from.
Do you have any suggestions or advice?
My app configuration:
package.json
"name": "app1",
"version": "0.1.0",
"private": true,
"dependencies": {
"#reduxjs/toolkit": "^1.8.1",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^12.1.4",
"#testing-library/user-event": "^13.5.0",
"history": "^5.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-redux": "^7.2.8",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.0",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
routes.js
import React, { Component } from 'react';
import Component1 from './functional/component1';
import Component2 from './functional/component2';
import Component3 from './functional/component3';
//import container home-page
import Container1 from './containers/container1';
import Header from './containers/header';
import history from './utils/history';
//react router import
import { Router, Route } from 'react-router';
class Routes extends Component {
render() {
return (
<div>
<Router history={history.location} navigator={history} >
<div>
<Header />
<Route path="/" component={Container1} />
<Route path="/component1" component={Component1} />
<Route path="/component2" component={Component2} />
<Route path="/component3" component={Component3} />
</div>
</Router>
</div>
)
}
}
export default Routes;
-history.js
var createHistory = require('history').createBrowserHistory;
export default createHistory();
Issue
The low-level Router takes a few different props than it did in v5.
Router
declare function Router(
props: RouterProps
): React.ReactElement | null;
interface RouterProps {
basename?: string;
children?: React.ReactNode;
location: Partial<Location> | string; // <-- required
navigationType?: NavigationType;
navigator: Navigator; // <-- required
static?: boolean;
}
Router source
export function Router({
basename: basenameProp = "/",
children = null,
location: locationProp, // <-- undefined location
navigationType = NavigationType.Pop,
navigator,
static: staticProp = false,
}: RouterProps): React.ReactElement | null {
...
let {
pathname = "/", // <-- cannot read "pathname" of undefined!
search = "",
hash = "",
state = null,
key = "default",
} = locationProp;
...
if (location == null) {
return null;
}
return (
<NavigationContext.Provider value={navigationContext}>
<LocationContext.Provider
children={children}
value={{ location, navigationType }}
/>
</NavigationContext.Provider>
);
}
You are incorrectly using a history prop instead of the location prop, and this is why location is undefined in the component and unable to read a pathname.
Additionally, in react-router-dom#6 the Route components necessarily need to be wrapped in the Routes component in order for route path matching and rendering to work.
Solution
Pass the correct required props and wrap the Route components in Routes component.
import React, { Component } from 'react';
import Component1 from './functional/component1';
import Component2 from './functional/component2';
import Component3 from './functional/component3';
//import container home-page
import Container1 from './containers/container1';
import Header from './containers/header';
import history from './utils/history';
//react router import
import { Router, Routes, Route } from 'react-router';
class Routes extends Component {
render() {
return (
<div>
<Router location={history.location} navigator={history} >
<div>
<Header />
<Routes>
<Route path="/" component={Container1} />
<Route path="/component1" component={Component1} />
<Route path="/component2" component={Component2} />
<Route path="/component3" component={Component3} />
</Routes>
</div>
</Router>
</div>
)
}
}
You are using react router v6 and in v6 you have to wrap all of your route's in <Routes>...</Routes> tag.
//react router import
import { Router, Route, Routes } from 'react-router'; // Make sure to import ----Routes----
class Routes extends Component {
render() {
return (
<div>
<Router history={history.location} navigator={history} >
<div>
<Header />
<Routes>
<Route path="/" component={Container1} />
<Route path="/component1" component={Component1} />
<Route path="/component2" component={Component2} />
<Route path="/component3" component={Component3} />
</Routes>
</div>
</Router>
</div>
)
}
}
export default Routes;
And you can't add anything between <Routes>...</Routes> except <Route />.
Related
Problem Summary
I am working on a MERN app.
So far I have built the backend, and just starting adding routes in the frontend.
After the process of adding routes to the frontend, an issue arose. The issue is that nothing shows up on the screen. In the Console, the following error shows:
Problem Details
Directory Snapshot 👇
The directory where my app is looks like this:
App.js 👇
// import bootstrap
import "bootstrap/dist/css/bootstrap.min.css";
// import Routers
import {BrowserRouter as Router, Route} from "react-router-dom";
import Navbar from "./components/navbar.component";
import ExerciseList from "./components/exercises-list.component";
import EditExercise from "./components/edit-exercise.component";
import CreateExercise from "./components/create-exercise.component";
import CreateUser from "./components/create-user.component";
function App() {
return (
<Router>
<Navbar/>
<br/>
<Route exact path="/" component={ExerciseList}/>
<Route path="/edit/:id" component={EditExercise}/>
<Route path="/create" component={CreateExercise}/>
<Route path="/user" component={CreateUser}/>
</Router>
);
}
export default App;
package.json 👇
{
"name": "exercise-tracker",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.3.0",
"#testing-library/user-event": "^13.5.0",
"bootstrap": "^5.1.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
navbar.component.js 👇
import React, {Component} from 'react'
import { Link } from 'react-router-dom';
export default class Navbar extends Component {
render() {
return (
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<Link to="/" className="navbar-brand">Exercise Tracker</Link>
<div className='collapse navbar-collapse'>
<ul className="navbar-nav mr-auto">
<li className="navbar-item"><Link to="/" className="nav-link">Exercises</Link></li>
<li className="navbar-item"><Link to="/create" className="nav-link">Create Exercise Log</Link></li>
<li className="navbar-item"><Link to="/user" className="nav-link">Create User</Link></li>
</ul>
</div>
</nav>
)
}
}
What I have tried
I tried following the steps on the console and wrapping in a in App.js (I also update App.js's line import {BrowserRouter as Router, Route} from "react-router-dom" to import {BrowserRouter as Router, Route, Routes} from "react-router-dom").
This solves the problem of the white page and the console errors. However, I do not see anything in the body (which is what I expect upon clicking the links in the navbar) and I see the following errors in the console:
At this point I did not know where to go.
In react-router-dom#6 the Route components can only be rendered by the Routes component or other Route components. The Route component API also changed significantly from v6, they render their content on a single element prop taking a ReactNode, a.k.a. JSX, value.
Wrap the Route components in a Routes component.
Render the routed components on the Route components' element prop as JSX
Example:
// import Routers
import {BrowserRouter as Router, Routes, Route} from "react-router-dom";
import Navbar from "./components/navbar.component";
import ExerciseList from "./components/exercises-list.component";
import EditExercise from "./components/edit-exercise.component";
import CreateExercise from "./components/create-exercise.component";
import CreateUser from "./components/create-user.component";
function App() {
return (
<Router>
<Navbar/>
<br/>
<Routes>
<Route path="/" element={<ExerciseList />} />
<Route path="/edit/:id" element={<EditExercise />} />
<Route path="/create" element={<CreateExercise />} />
<Route path="/user" element={<CreateUser />} />
</Routes>
</Router>
);
}
See the Migrating from v5 guide for further breaking changes in v6.
I'm creating a React project and I want to implement the BrowserRouter but the problem is that when I used it, it always throw the React Error of:
***Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.***
I don't know what is this about, because as far as I know, I'm not using hooks and I read the documentation and other tutorials to solve this problem (like deleting double react or npm link and that's stuff) but this still a problem.
Here are my files.
App.js
import { BrowserRouter, Route, Routes, Link } from "react-router-dom";
import Navbar from "./components/navbar"
import Login from "./components/login";
// import CreateExercise from "./components/create-exercise.component";
// import CreateUser from "./components/create-user.component";
function App() {
return (
// <h1>HOASNKFNLSA</h1>
// <div>
// <Home/>
// </div>
<BrowserRouter>
<Routes>
<Route path="/" render={() => {
<h1>HOKAKSFNAKSO</h1>
}}>
</Route>
</Routes>
</BrowserRouter>
);
}
function Home() {
return (
<div className="container text-center">
<h1>KEVIN STYLE PELUQUERIA</h1>
</div>
);
}
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
</div>
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
package.json
{
"name": "kevin-style-peluqueria",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^5.16.1",
"#testing-library/react": "^11.2.7",
"#testing-library/user-event": "^12.8.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
I don't know if you need anything else, but if you do, ask me in comments. If you need to know more extra info, I'm not using webpack. I'm using the classic React structure application when you do the command npx create-react-app. I'm also using express and MongoDB like my backend (basically I'm creating an application with the MERN Stack).
You should do something like this.
And take a look to the docs with examples
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter as Router } from 'react-router-dom'
ReactDOM.render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
My problem is that react-router-dom is working for Homepage and productList but not working for Signin component. I think there is no problem with snowpack. But I put snowpack config file, in case there is some problem. The weird thing is I added a Header for Homepage and product list but I didn't added the header for Signin component. but after changing the route, header is showing even I didn't add Header into the Signin Component. I am so confused that why this is happening.
App.jsx
import React from 'react';
import Homepage from './Containers/Homepage';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import ProductList from './Containers/ProductList';
import Signin from './Containers/Signin';
function App() {
return (
<div className="App">
<Router>
<Switch>
<Route path="/" exact component={Homepage} />
<Route path="/:slug" component={ProductList} />
<Route exact path="/signin" component={Signin} />
</Switch>
</Router>
</div>
);
}
export default App;
Signin.jsx
import { Typography } from '#material-ui/core';
import React from 'react';
import Layout from '../Components/Layout';
const Signin = () => {
return (
<div
style={{
marginTop: '10rem',
paddingTop: '10rem',
background: 'black',
height: '100vh',
}}
>
Signin
</div>
);
};
export default Signin;
Header.jsx
this file is big. but I'm adding the route call.
const handleButtonClick = (pageURL) => {
history.push(pageURL);
};
<Button variant="contained" onClick={() => handleButtonClick('/signin')}>
Login
</Button>;
snowpack.config.js
/** #type {import("snowpack").SnowpackUserConfig } /
module.exports = {
mount: {
/ ... /
public: "/",
src: "/dist",
},
plugins: ["#snowpack/plugin-react-refresh"],
routes: [
{ match: "all", src: "/api/.", dest: (req, res) => proxy.web(req, res) },
{ match: "routes", src: ".", dest: "/index.html" },
],
optimize: {
/ Example: Bundle your final build: /
// "bundle": true,
},
packageOptions: {
polyfillNode: true,
},
devOptions: {
port: 3000,
},
buildOptions: {
/ ... */
},
};
package.json
{
"name": "ecommerce-website",
"version": "0.1.0",
"private": true,
"dependencies": {
"#material-ui/core": "^4.11.4",
"#material-ui/icons": "^4.11.2",
"#snowpack/plugin-webpack": "^2.3.1",
"#testing-library/jest-dom": "^5.12.0",
"#testing-library/react": "^11.2.6",
"#testing-library/user-event": "^12.8.3",
"axios": "^0.21.1",
"formik": "^2.2.6",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-icons": "^4.2.0",
"react-query": "^3.13.12",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.2",
"yup": "^0.32.9"
},
"scripts": {
"start": "snowpack dev",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": ["react-app", "react-app/jest"]
},
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"#snowpack/plugin-react-refresh": "^2.5.0",
"snowpack": "^3.3.7"
}
}
Any help will be appreciated before I punch my Laptop Screen. Thanks.
The problem is with
<Route path="/:slug" component={ProductList} />
<Route exact path="/signin" component={Signin} />
/:slug as first route accepts everything and renders the productList on every request other than / Homepage because of the exact attribute.
You can interchange its position with the signIn component to get the correct Component Rendering. Like this
<Route exact path="/signin" component={Signin} />
<Route path="/:slug" component={ProductList} />
This route:
<Route path="/:slug" component={ProductList} />
Is a match for /signin, where signin is treated as the parameter :slug. In fact, this route will match pretty much any path except /, because you don't have an exact prop. The path /a/b/c/d is a match, where a is the parameter :slug.
I would restructure the switch to look like this:
<Switch>
<Route path="/" exact component={Homepage} />
<Route exact path="/signin" component={Signin} />
<Route path="/:slug" component={ProductList} />
</Switch>
It will now choose the first matching path, which is your static route. I would also potentially make the /:slug path exact as well if you are not expecting to match all paths here.
My app was built using create-react-app. It all works fine once I'm using the app except when I click on the link from my portfolio website (on MAMP local host), it loads the custom 404 page instead of the Home component. When I load the app from npm run start it lands on the Home component first, I want it to do this on localhost and my live website too.
I've tried changing the "homepage" in package.json to "." but it still does the same thing.
// App.js
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Header from './components/layout/Header';
import NotFound from './components/layout/NotFound';
import Alert from './components/layout/Alert';
import Home from './components/content/Home';
import Movie from './components/content/movies/Movie';
import AlertState from './context/alert/AlertState';
import MovieState from './context/movies/MovieState';
const App = () => {
return (
<MovieState>`enter code here`
<AlertState>
<Router>
<Header text={"Movie App"}/>
<Alert />
<Switch>
<Route path='/' component={Home} />
<Route path='/movie/:title' component={Movie} />
<Route component={NotFound} />
</Switch>
</Router>
</AlertState>
</MovieState>
);
}
export default App
package.json
{
"name": "film_app",
"version": "0.1.0",
"homepage": ".",
"dependencies": {
"axios": "^0.19.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-router-dom": "^5.0.1",
"react-scripts": "3.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
// Home.js
import React from 'react';
import Search from './Search';
import Movies from './movies/Movies';
const Home = () => {
return (
<>
<Search />
<Movies />
</>
)
}
export default Home
// NotFound.js
import React from 'react';
const NotFound = () => {
return (
<div>
<h1>
Page Not Found
<p className='lead' style={notFoundStyles}>
The page you are looking for does not exist
</p>
</h1>
</div>
)
}
const notFoundStyles = {
textAlign: 'center',
};
export default NotFound
There is no error message, it just shows the NotFound component rather than the Home component.
Add exact flag to your Home route, and path='/' to the fallback route.
<Switch>
<Route path='/' exact={true} component={Home} />
<Route path='/movie/:title' component={Movie} />
<Route path='/' component={NotFound} />
</Switch>
I started learning React and React Router by making basic application but I am getting warnings that I am not able to resolve
Warning 1: React.createElement: type is invalid -- expected a string
(for built-in components) or a class/function (for composite components)
but got: undefined.
Warning 2: Failed prop type: The prop `history` is marked as required
in `Router`, but its value is `undefined`.
My code :
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import routes from './routes'
ReactDOM.render(routes, document.getElementById('app'));
.
routes.js
import React from 'react'
import { Route } from 'react-router'
import Home from './components/home';
import Login from './components/login'
const routes = (
<Route path="/" component={Home}>
<Route path="/login" component={Login} />
</Route>
);
export default routes;
.
home.js
import React from 'react'
export default React.createClass({
render(){
return (
<div>
<h1>Hello From Home</h1>
</div>);
}
});
login.js
import React from 'react'
export default React.createClass({
render(){
return (<h1>Hello From Login Page</h1>);
}
});
this is my
package.json
{
"name": "basicapp",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"production": "webpack -p",
"start": "webpack-dev-server"
},
"author": "aviaTorX",
"license": "ISC",
"dependencies": {
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-router": "^4.0.0"
},
"devDependencies": {
"babel-core": "^6.24.0",
"babel-loader": "^6.4.0",
"babel-preset-react": "^6.23.0",
"html-webpack-plugin": "^2.28.0",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.2"
}
}
It is giving Blank screen with warnings above mentioned.
if you're using react-router ^4.0.0, your root component need
a Router element. It is seems missing from your routes.js file.
Your routes.js should look like this:
import React from 'react'
import { Route, BrowserRouter as Router } from 'react-router'
import Home from './components/home';
import Login from './components/login'
const routes = (
<Router>
<Route path="/" component={Home}>
<Route path="/login" component={Login} />
</Route>
</Router>
);
export default routes;
Your routes.js should be
import React from 'react'
import {
Route,
Router,
IndexRoute,
hashHistory
} from 'react-router'
import Home from './components/home';
import Login from './components/login'
export const routes = () => {
return(
<Router history={hashHistory}>
<IndexRoute component={Home} />
<Route path="/login" component={Login} />
</Router>
);
};
export default routes;
You can directly use this.props.history.push('/list/').
But remember that, the version of my react-router is ^4.2.0.