I have an application built in React and Redux that's been working fine until I implemented a simple localStorage check to render either the App or an auth page I've called Gateway:
App.js
import React, { useState } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { Provider } from "react-redux";
import store from "./redux/store";
import NavBar from "./components/NavBar";
import Settings from "./views/Settings";
import Gateway from "./views/Gateway";
import Profile from "./views/Profile";
import Signup from "./views/Signup";
import NewTestimonialPage from "./views/NewTestimonialPage";
import NotFoundPage from "./views/NotFoundPage";
import "./styles/App.scss";
function App() {
// new additions start here...
const [loggedIn, setLoggedIn] = useState(
localStorage.getItem("loggedIn") === "true"
);
if (!loggedIn) {
return <Gateway />;
}
...and end here
return (
<Router>
<Provider store={store}>
<NavBar />
<div className="navbar-dodger"></div>
<div className="App">
<Switch>
<Route exact path="/" component={Gateway} />
<Route path="/signup" component={Signup} />
<Route path="/settings/:userId" component={Settings} />
<Route path="/profile/:userId" component={Profile} />
<Route
path="/new-testimonial/:userId"
component={NewTestimonialPage}
/>
<Route path="/404" component={NotFoundPage} />
<Route component={NotFoundPage} />
</Switch>
</div>
</Provider>
</Router>
);
}
export default App;
Without the code between comments, everything was 100% fine.
Now, I throw this error:
Could not find "store" in the context of "Connect(EmailCheck)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(EmailCheck) in connect options.
If I render the provider inside that if-block as well, it works. Why? Why do I need a store if I'm not using redux in any way inside Gateway?
If you are using redux inside <Gateway> component then your component must be wrapped in <Provider>
It should look like :
return (
<Router>
<Provider store={store}>
{!loggedIn ?? <Gateway /> : <YourApplication />}
</Provider>
</Router>
);
Create a component for the app like
YourApplication.js:
return (
<>
<NavBar />
<div className="navbar-dodger"></div>
<div className="App">
<Switch>
<Route exact path="/" component={Gateway} />
<Route path="/signup" component={Signup} />
<Route path="/settings/:userId" component={Settings} />
<Route path="/profile/:userId" component={Profile} />
<Route
path="/new-testimonial/:userId"
component={NewTestimonialPage}
/>
<Route path="/404" component={NotFoundPage} />
<Route component={NotFoundPage} />
</Switch>
</div>
<>
);
Related
I'm programming in react, the truth is the first time that I program it in React.
in App.js I define the routes, I use the react-router-dom library, but I get the error of the title, the code is the following, what am I doing wrong, can you explain it to me, because I bring all the components.
import React from 'react';
import './App.css';
import 'materialize-css/dist/css/materialize.css';
import NavBar from './components/NavBar';
import ItemListContainer from './components/ItemListContainer';
import MoreSell from './components/ItemListMoreSell';
import ItemDetailContainer from './components/ItemDetailContainer';
import Cart from './components/Cart';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<div className="App">
<BrowserRouter>
<NavBar />
<MoreSell/>
<Routes>
<Route path="/" element={<ItemListContainer/>} />
<Route path="/category/:categoryID" element={<ItemListContainer/>} />
<Route path="/detail/:productID" element={<ItemDetailContainer/>} />
<Route path="/cart" element={<Cart/>} />
<ItemListContainer/>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
Thank you
ItemListContainer is causing the problem after the Cart route, since inside Routes you can only define route
function App() {
return (
<div className="App">
<BrowserRouter>
<NavBar />
<MoreSell/>
<Routes>
<Route path="/" element={<ItemListContainer/>} />
<Route path="/category/:categoryID" element={<ItemListContainer/>} />
<Route path="/detail/:productID" element={<ItemDetailContainer/>} />
<Route path="/cart" element={<Cart/>} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
You have ItemListContainer/> as a child inside Routes>. Either delete this component, move it outside of Routes, or create a new route with it inside.
<Routes>
<Route path="/" element={<ItemListContainer/>} />
<Route path="/category/:categoryID" element={<ItemListContainer/>} />
<Route path="/detail/:productID" element={<ItemDetailContainer/>} />
<Route path="/cart" element={<Cart/>} />
<ItemListContainer/> //<-------------------------This is the error
</Routes>
I think the answer in your error message:
you need to remove < ItemListContainer /> from < Routes > ... </ Routes > container and move it to another place. For example:
function App() {
return (
<div className="App">
<BrowserRouter>
<NavBar />
<MoreSell/>
<Routes>
<Route path="/" element={<ItemListContainer/>} />
<Route path="/category/:categoryID" element={<ItemListContainer/>} />
<Route path="/detail/:productID" element={<ItemDetailContainer/>} />
<Route path="/cart" element={<Cart/>} />
</Routes>
<ItemListContainer/>
</BrowserRouter>
</div>
);
}
I am working on a web application and my application works for the most part except I cannot see the /tasks section. I do not understand because it is the same as the rest of my elements.
import React, {
Component,
Fragment
} from 'react';
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom';
import AppProvider, {
Consumer
} from './AppProvider';
import Login from './Login';
import Signup from './Signup';
import Navbar from './Navbar';
import FlashMessage from './FlashMessage';
class App extends Component {
render() {
return (
<AppProvider>
<Router>
<Fragment>
<Navbar />
<FlashMessage />
<Route exact path="/" component={() =>
<h1 className="content">Welcome, Home!</h1>} />
<Route exact path="/login" component={() => <Login />} />
<Route exact path="/signup" component={() => <Signup />} />
<Router exact path="/tasks" component={() =>
<h1 className="content">Content Should Go Here</h1>} />
<Route exact path="/signedOut" component={() =>
<h1 className="content">You're now signed out.</h1>} />
<Route exact path="/accountCreated" component={() =>
<h1 className="content">Account created. <Link
to="/login">
Proceed to Dashboard</Link></h1>} />
</Fragment>
</Router>
</AppProvider>
);
}
}
export default App;
The content div routed at /tasks won't display anything. There are no errors, I have checked in the console. All I want is it to display the content on /tasks.
I think the problem is you are using the BrowserRouter in your "./tasks" instead of use route.
The issue is because you have a trailing Slash on your link.
I created the component NotFound and it works fine when I go to a page that doesn't exist. But the same page it's appearing in all my pages, not only the one that doesn't exist. This is the component:
import React from 'react'
const NotFound = () =>
<div>
<h3>404 page not found</h3>
<p>We are sorry but the page you are looking for does not exist.</p>
</div>
export default NotFound
And this is how I used it in the main page:
class MainSite extends Component {
render () {
return (
<div>
{/* Render nav */}
<Route path='/dashboard' component={Nav} />
<Route path='/retrospectives' component={Nav} />
<Route path='/users' component={Nav} />
<Route path='/projects' component={Nav} />
{/* Dashboard page */}
<ProtectedRoute exact path='/dashboard' component={DashboardPage} />
{/* Retrospectives page */}
<ProtectedRoute exact path='/retrospectives' component={RetrospectivesPage} />
{/* Users page */}
<ProtectedRoute exact path='/users' component={UsersPage} />
{/* Projects page */}
<ProtectedRoute exact path='/projects' component={ProjectsPage} />
{/* Retrospective related pages */}
<Route exact path='/retrospectives/:retrospectiveId' component={Retrospective} />
<Route exact path='/join-retrospective' component={JoinRetrospective} />
<ProtectedRoute exact path='/create-retrospective/:retrospectiveId' component={Retrospective} />
{/* OnBoarding pages */}
<ProtectedRoute exact path='/beta-code' component={BetaCodeAccess} />
<Route exact path='/auth-handler' component={AuthHandler} />
<Route exact path='/join-organization' component={JoinOrganization} />
</div>
)
}
}
export default MainSite
As you can see I use <Route path="*" component={NotFound} /> to create the 404 pages, but that component is appearing in every existing page as well. How can I fix this?
Try this one:
import { Switch, Route } from 'react-router-dom';
<Switch>
<Route path='/dashboard' component={Nav} />
<Route path='/retrospectives' component={Nav} />
<Route path='/users' component={Nav} />
<Route path='/projects' component={Nav} />
<Route path="" component={NotFound} />
</Switch>
All below example works fine:
<Route path="" component={NotFound} /> // empty ""
<Route path="*" component={NotFound} /> // star *
<Route component={NotFound} /> // without path
Or if you want to return a simple 404 message without any component:
<Route component={() => (<div>404 Not found </div>)} />
For those who are looking for an answer using react-router-dom v6, many things had changed. Switch for example doesn't exists anymore, you have to use element instead of component, ... Check this little example to get you an idea:
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import './index.css'
import App from './App'
const Test = () => (
<h1>404</h1>
)
ReactDOM.render(
<React.StrictMode>
<Router>
<Routes>
<Route path='/' element={<App />} />
<Route path='*' element={<Test />}/>
</Routes>
</Router>
</React.StrictMode>,
document.getElementById('root')
)
With this you are defining your home route and all the other routes will show 404. Check the official guide for more info.
Try This:
import React from "react";
import { Redirect, Route, Switch, BrowserRouter } from 'react-router-dom';
import HomePage from './pages/HomePage.jsx';
import NotFoundPage from './NotFoundPage.jsx';
class App extends React.Component {
render(){
return(
<BrowserRouter>
<Switch>
<Route exact path='/' component={HomePage} />
<Route path="*" component={NotFoundPage} />
</Switch>
</BrowserRouter>
)
}
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Simply import Switch from react-router-dom and wrap all your Routes in the Switch Component. Also Important here is to note to keep your 404Page component at the very bottom(just before your switch ending tag) This way it will match each component with its route first. If it matches, it will render the component or else check the next one. Ultimately if none matching routes will be founded, it will render 404Page
react router is a headache for new coders. Use this code format. This is class component but you can make a functional component and use it.
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import HomePage from './pages/HomePage.jsx';
import NotFoundPage from './NotFoundPage.jsx';
import Footer from './Footer';
class App extends React.Component {
render(){
return(
<Router>
<Routes>
<Route exact path='/' element={HomePage} />
<Route path="*" element={NotFoundPage} />
</Routes>
<Routes>
<Route path="/" element={Footer}/>
</Routes>
</Router>
)
}
}
export default App;
I'm updating my universal react redux app to use react router v4. I have nested routes under a main layout route. Previously I used {props.children} to show contents of child routes, but this doesn't work anymore. How does this work in V4?
<Provider store={store} key="provider">
<div>
<Route component={Layout} />
<Switch>
<Route path="/" component={HomePage} />
<Route component={Error404} />
</Switch>
</div>
</Provider>
or
<Provider store={store} key="provider">
<Layout>
<Route path="/" component={HomePage} />
<Route component={Error404} />
</Layout>
</Provider>
This is how my Layout file looks
const Layout = props => (
<div className="o-container">
<Header />
<main>
{props.children}
</main>
<Footer />
</div>
);
I have taken the <Provider>out because it belongs to react-redux and you don't need it as basis for routing with react-router (anyway you can easily add it encapsulating the structure with it).
In React Router V4, what was Router has been renamed to BrowserRouter and imported from package react-router-dom. So for nesting routes you need to insert this as children of your <Layout>.
index.js
import { Switch, Route } from 'react-router';
import { BrowserRouter } from 'react-router-dom';
import Layout from './Layout';
...
const Root = () => (
<Layout>
<BrowserRouter>
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/other" component={OtherComponent} />
<Route component={Error404} />
</Switch>
</BrowserRouter>
</Layout>
);
ReactDOM.render(
<Root/>,
document.getElementById('root')
);
Layout.js
import React from 'react';
import Header from './Header';
import Footer from './Footer';
const Layout = props => ({
render() {
return (
<div className="o-container">
<Header />
<main>{props.children}</main>
<Footer />
</div>
);
}
});
export default Layout;
Take in count this only works for web. Native implementation differs.
I uploaded a small project based in Create React App where I show the implementation of nested routes in V4.
Just thought I have to share this. If you're using a Link component in your Header component. The answer above won't work. You would have to make the BrowserRouter as the parent again to support Link. Make it like this:
<BrowserRouter>
<Layout>
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/other" component={OtherComponent} />
<Route component={Error404} />
</Switch>
</Layout>
</BrowserRouter>
I would use this structure, without props.children :
const Main = () => (
<main>
<Switch>
<Route exact path="/" component={HomePage} />
<Route component={Error404} />
</Switch>
</main>
)
const Layout = () => (
<div>
<Header />
<Main />
<Footer />
</div>
)
ReactDOM.render((
<Provider store={store}>
<BrowserRouter>
<Layout />
</BrowserRouter>
</Provider>
), document.getElementById('root'))
Please read this blog through. https://codeburst.io/react-router-v4-unofficial-migration-guide-5a370b8905a
No More <IndexRoute>
The component allowed to route to a certain component on a top-level path in v3:
// in src/MyApp.js
const MyApp = () => (
<Router history={history}>
<Route path="/" component={Layout}>
<IndexRoute component={Dashboard} />
<Route path="/foo" component={Foo} />
<Route path="/bar" component={Bar} />
</Route>
</Router>
)
This component doesn’t exist anymore in v4. To replace it, use a combination of , exact, and route ordering (placing the index route last):
// in src/MyApp.js
const MyApp = () => {
<Router history={history}>
<Route path="/" component={Layout} />
</Router>
}
// in src/Layout.js
const Layout = () => (
<div className="body">
<h1 className="title">MyApp</h1>
<div className="content">
<Switch>
<Route exact path="/foo" component={Foo} />
<Route exact path="/bar" component={Bar} />
<Route exact path="/" component={Dashboard} />
</Switch>
</div>
</div>
);
Adding to #Dez answer
Complete native / core implementation with Redux support
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, Switch } from 'react-router';
import createMemoryHistory from 'history/createMemoryHistory';
const history = createMemoryHistory();
import App from './components/App';
import Home from './components/Home';
import Login from './components/Login';
import store from './store';
ReactDOM.render((
<Provider store={ store }>
<Router history={history}>
<App>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
</Switch>
</App>
</Router>
</Provider>
), document.getElementById('root'));
App.js
import Header from './Header';
import Home from './Home';
import React from 'react';
import {connect} from 'react-redux';
const mapStateToProps = state => ({appName: state.appName});
class App extends React.Component {
render() {
return (
<div >
<Header appName={this.props.appName} /> {/*common header*/}
{this.props.children}
</div>
);
}
}
export default connect(mapStateToProps, () => ({}))(App);
If using with Redux, without the Switch element
AppRouter.js
import React from 'react'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
const AppRouter = () => (
<Layout>
<Router>
<div>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/contact" component={Contact}/>
</div>
</Router>
</Layout>
)
export default AppRouter;
Layout.js
const Layout = props => ({
render() {
return (
<div className="container">
<Header />
<main>{props.children}</main>
<Footer />
</div>
);
}
});
export default Layout;
Provider placed in Render function
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import AppRouter from './AppRouter';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware()(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<AppRouter />
</Provider>
, document.getElementById('app'));
I keep on getting the error:
A 'Router' may have only one child element
when using react-router.
I can't seem to figure out why this is not working, since it's exactly like the code they show in their example: Quick Start
Here is my code:
import React from 'react';
import Editorstore from './Editorstore';
import App from './components/editor/App';
import BaseLayer from './components/baselayer';
import {BrowserRouter as Router, Route} from 'react-router-dom';
import {render} from 'react-dom';
const root = document.createElement('div');
root.id = 'app';
document.body.appendChild(root);
const store = new Editorstore();
const stylelist = ['https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css', 'https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.2/semantic.min.css', 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css', 'https://api.tiles.mapbox.com/mapbox-gl-js/v0.33.1/mapbox-gl.css'];
stylelist.map((link) => {
const a = document.createElement('link');
a.rel = 'stylesheet';
a.href = link;
document.body.appendChild(a);
return null;
});
render((
<Router>
<Route exact path="/" component={BaseLayer} />
<Route path="/editor" component={App} store={store} />
</Router>
), document.querySelector('#app'));
You have to wrap your Route's in a <div>(or a <Switch>).
render((
<Router>
<Route exact path="/" component={BaseLayer} />
<Route path="/editor" component={App} store={store} />
</Router>
), document.querySelector('#app'));
should be
render((
<Router>
<div>
<Route exact path="/" component={BaseLayer} />
<Route path="/editor" component={App} store={store} />
</div>
</Router>
), document.querySelector('#app'));
jsfiddle / webpackbin
This is an API change in react-router 4.x. Recommended approach is to wrap Routes in a Switch: https://github.com/ReactTraining/react-router/issues/4131#issuecomment-274171357
Quoting:
Convert
<Router>
<Route ...>
<Route ...>
</Router>
to
<Router>
<Switch>
<Route ...>
<Route ...>
</Switch>
</Router>
You will, of course, need to add Switch to your imports:
import { Switch, Router, Route } from 'react-router'
I Always use Fragment in react web and native ( >= react 16 )
import React, { Component, Fragment } from 'react'
import { NativeRouter as Routes, Route, Link } from 'react-router-native'
import Navigation from './components/navigation'
import HomeScreen from './screens/home'
import { RecipesScreen } from './screens/recipe'
class Main extends Component {
render() {
return (
<Fragment>
<Navigation />
<Routes>
<Fragment>
<Route exact path="/" component={HomeScreen} />
<Route path="/recipes" component={RecipesScreen} />
</Fragment>
</Routes>
</Fragment>
)
}
}
export default Main
I put all my <Route /> tags inside the <Switch> </Switch> tag like this.
<BrowserRouter>
<Switch>
<Route path='/' component={App} exact={true} />
<Route path='/form-example' component={FormExample} />
</Switch>
</BrowserRouter>
This solves the problem.
If you are nesting other components inside the Router you should do like.
<Router>
<div>
<otherComponent/>
<div>
<Route/>
<Route/>
<Route/>
<Route/>
</div>
</div>
</Router>
If you are using Reach Routers make sure the Code looks like this:
<Router>
<Login path="/" />
<Login path="/login" />
</Router>
Including these Components in a Div in the case of React Routers will make this work but In Reach Routers, Remove that Div Element.
you can also wrap all your route in a parent route which defaults to index page
<Router history={history}>
<Route path="/" component={IndexPage}>
<Route path="to/page" component={MyPage}/>
<Route path="to/page/:pathParam" component={MyPage}/>
</Route>
</Router>
I am using react-router-dom package with version 5.0.1 and it works perfectly fine with your code.
import { BrowserRouter as Router , Router, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
...
class App extends React.Component {
render() {
return (
<Router>
<ul>
<li><Link path='/'>Home</Link></li>
<li><Link path='/about'>About</Link></li>
</ul>
<Route path='/' exact component={Home} />
<Route path='/about' component={About} />
</Router>
);
}
}
export default App;
Not sure if my router might be too simple, or there was a change to this rule but was following along a tutorial that mentioned this limitation (A 'Router' may have only one child element) and it allowed me to add 3 routes without giving any errors. This is the working code:
function render() {
ReactDOM.render(
<BrowserRouter>
<Route exact path="/" component={App} />
<Route path="/add" component={AddAuthorForm} />
<Route path="/test" component={test} />
</BrowserRouter>
,
document.getElementById('root')
);
}
And this are my dependencies:
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.1",
This problem occurs when you don't have parent tag before <Route>inside <Router> so to resolve this problem keep the <Route>enclosed in a parent tag such as <div> , <p> etc.
Example -
<Router>
<p>
<Route path="/login" component={Login} />
<Route path="/register" component={Register} />
</p>
</Router>