im trying to format my HTML like so within the body tag:
<header id="header"></header>
<main id="app"></main>
<footer id="footer"></footer>
reason why is so that i have my navigation out of <main></main> and in <header></header>
Im also rendering the corresponding React component individually i.e: document.getElementById("header"), document.getElementById("app") ...:
ReactDOM.render(
<Header />,
document.getElementById("header")
);
When clicking <Link to="/log-in"></Link> in <Header /> it breaks out of SPA and jumps to /log-in page.
What am i missing here?
Using ReactDOM.render multiple times will create separate instances unaware of each other source.
Let's go on about restructuring that a bit to make your app feel better:
App.js
import React from 'react';
import { Main } from './components';
const App = () => (
<Main />
)
ReactDOM.render(<App />, document.getElementById("app"));
Main.js
import React from 'react';
import { Router, Route } from 'react-router-dom';
import { Header, Login, Register, Home } from './components'
const Main = () => (
<Router>
<React.Fragment>
<Header />
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
<Route path="/register" component={Register} />
<Footer />
</React.Fragment>
</Router>
)
export { Main };
So this way, we're ever only really rendering one instance. Your header/footer would be placed outside of the router, so whenever the route changes, they remain unaffected. Keep in mind that this will present a challenge, eg if you want your Header to highlight which route is active, the simples way, since it's outside of router and doesn't receive props from it, is to check the url. Also note that we're using <React.Fragment> here, but you're free to use a <div> or anything else you like. Router expect one child only, so if you don't want additional html elements, you can use a fragment!
Related
I am trying to make a website by watching tutorial in Udemy.
The instructor added Route in one of the file, and I did the same, but my webpage becomes blank after adding it.
I also tried including Routes but that didn't help.
Here's my code:
import { Container } from 'react-bootstrap';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Header from './components/Header';
import Footer from './components/Footer';
import HomeScreen from './screens/HomeScreen';
function App() {
return (
<Router>
<Header />
<main classname="py-3">
<Container>
<Routes>
<Route path="/" element={<HomeScreen />} />
</Routes>
</Container>
</main>
</Footer />
</Router>
);
}
export default App;
enter image description here
It looks like you may be using react-router-dom#6. The Routes component API changed significantly from v5 to v6, it no longer takes a component, or render or children function props, all replaced by a single element prop taking a ReactNode, a.k.a. JSX. Note that in RRDv6 that all routes are now always exactly matched, so there is also no longer any exact prop.
Example:
<Router>
<Header />
<main classname="py-3">
<Container>
<Routes>
<Route path="/" element={<HomeScreen />} />
</Routes>
</Container>
</main>
</Footer />
</Router>
I know several questions have been asked relating to this, but none capture what I am experiencing so here it goes...
My app loads fine and my landing page is rendering as expected. The weird piece is that none of the other routes are loading. I have a react-router-dom Link on the Landing component that directs to school but nothing happens, no console errors, just the Landing component still rendering. When I manually type any other route in the browser, still nothing happens, just the Landing pages rendering.
It doesn't matter what component is set to the / route, it renders fine but something is definitely up with the react-router-dom.
Here's my index.js
import { render } from 'react-dom';
import App from './components/app/App';
import './index.scss';
render(
<App />,
document.getElementById('root'),
);
App.js
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
import Content from '/components/Content';
import Nav from '../nav/Nav';
import Home from '../../pages/home/Home';
import PageFooter from '../footer/PageFooter';
import Search from '../../pages/search/Search';
import Course from '../../pages/course/Course';
import Landing from '../../pages/landing/Landing';
export default function App() {
return (
<div className="App">
<BrowserRouter>
<Nav />
<Content className="main-wrapper" fullWidth>
<Routes>
<Route path="/" element={<Landing />} />
<Route path="school" element={<Home />} />
<Route path="search" element={<Search />} />
<Route path="courses">
<Route path=":courseId" element={<Course />} />
<Route
index
element={<Navigate replace to="/" />}
/>
</Route>
</Routes>
</Content>
<PageFooter />
</BrowserRouter>
</div>
);
}
I am absolutely beside myself - what am I doing wrong?
As it usually goes, this was my error. After ripping it all out, starting with a fresh CRA app, and piecing my project back together, I found that in the <Nav /> component I had an inappropriate math operator (= instead of ===) going on within a useLocation reference 🤦🏽
I have layout that header and footer components named as MainLayout.
This layout used in Home page.
I want to make another layout that named SubLayout.
This is not have header component, and used in About page.
How to make 2 different layout?
This is what I tried so far below.
Router.js
import React from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import MainLayout from '../components/layouts/MainLayout'
import Home from '../views/home/Home'
import About from '../views/about/About'
export default function Router1() {
return (
<Router>
<Switch>
<Route>
<MainLayout>
<Switch>
<Route path='/' exact component={Home} />
<Route path='/about' component={About} />
</Switch>
</MainLayout>
</Route>
</Switch>
</Router>
)
}
MainLayout
import React from 'react'
import Header from '../../components/layouts/Header'
import Footer from '../../components/layouts/Footer'
export default function Layout({ children }) {
return (
<div className="wrapper">
<Header />
<div className="container">
<div className="content">
{children}
</div>
</div>
<Footer />
</div>
)
}
SubLayout.js
import React from 'react'
import Footer from '../../components/layouts/Footer'
export default function Layout({ children }) {
return (
<div className="wrapper">
<div className="container">
<div className="content">
{children}
</div>
</div>
<Footer />
</div>
)
}
This is not a trivial problem and happens to a lot of website, especially after you have quite a bit pages.
Solution 1
Coding the layout in MainLayout is difficult since you basically have to fix every possible case of this website from now on, which is a challenge.
In order to avoid that, you can have a separate layout component for each page. ex.
export default function Page1() {
return (
<Header />
<YourPage1Content />
)
}
Although this is a bit extra work for each page, it's very flexible. And the solution is highly scalable no matter how many pages (or features, or sites) that you want to support. For example, you can even wire with entirely different header if you want for a particular page.
Solution 2
If you are looking for a generic way of solving this problem and still want to have a MainLayout since this is the wrapper for every pages, it can be done via Context.
export default function MainLayout() {
const { hideHeader } = useContext(LayoutContext)
return (
<>
{!hideHeader && <Header />}
{children}
</>
)
The context will be provided to you via route, or any custom Context.Provider which can be setup in your App.js or index.js
For instance for a particular route,
export default function MainLayout() {
const location = useLocation()
const hideHeader = location.pathname === '/'
return (
<>
{!hideHeader && <Header />}
{children}
</>
)
This approach is quite generic and highly scalable as well, as long as the same context is used for the entire site.
Summary
If you don't know what site you are building, use solution 1, it'll meet any requirement along the way. However if you have a specific need to meet, solution 2 is really pretty to make sure you can live with a generic Layout component.
All in all, it's about how many Layout component you'd like to reuse.
You can wrap either your whole component with the specific layout or you can wrap the route with specific layout to differentiate like,
export default function Router1() {
return (
<Router>
<Switch>
<MainLayout>
<Route path='/' exact component={Home} />
</MainLayout>
<SubLayout>
<Route path='/about' component={About} />
</SubLayout>
</Switch>
</Router>
)}
And there are unnecessary switch and route statements, cleaned it up a little.
I am trying to navigate to /movie/:title on which I am rendering a new page. But it only renders if my movie page i.e /movie renders, but I don't want my movie page to be mounted on navigating to /movie/:title. I only want it as part of the path. Making the /movie path exact doesn't work as /movie/:title wouldn't render with /movie as exact.
App.js
class App extends React.Component {
render() {
return (
<div>
<Header />
<Route path='/movies' component={Movies} />
<Route path='/tvshows' component={TvShow} />
</div>
)}
Movie.js
return (
<div className="movies">
<Route path={`${match.path}`} render={(props) => <CollectionGrid movies/>} />
<Route path={`${match.path}`} render={(props) => <CollectionOverview movies/>} />
<Route path={`${match.path}/:title`} component={ItemPage} />
</div>
);
A couple of notes. Conventionally, you should keep all your routes in a single router, thus making it easier to navigate and identify your application.
Organize your Router like this:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Home from "./Home";
import Movies from "./Movies";
import ItemPage from "./ItemPage";
const App = () => {
return (
<BrowserRouter>
<div>
<Switch>
<Route path="/" component={Home} exact />
<Route path="/movies/:title" component={ItemPage} />
<Route path="/movies" component={Movies} />
</Switch>
</div>
</BrowserRouter>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Additionally, to resolve your solution, you would need the Switch component, which is available in react-router-dom. The Switch component, will look through a list of Routes and will only render the FIRST Route who's path string is included within the URL string.
In the list above we have 3 Routes. If your URL is "/movies/blah", it will only render the ItemPage component, because that Route's path was matched first within the list.
We moved the "/movies/:title" Route before the regular "/movies" for this very reason. If the "/movies" Route appeared first in the list and if your URL was "/movies/blah", it would still satisfy the "/movies" Route. That means Switch would only render Movies component, which is not what you want.
See working sandbox: https://codesandbox.io/s/hopeful-bogdan-lzl76
you are not able to access to match direct in this app the match is found in this .props.match
you cand used it in
const App({match})
then when you need to used it should
<Route path={`${match.path}`} render={(props) => <CollectionGrid movies/>} />
look to this example and explain
I've been following this tutorial for creating a react project. The tutorial led to creating multiple react components that have a simple sample text within them. This would allow for the testing of the react-router-dom.
example of the simple component, all other components are similar.
import React, { Component } from 'react'
export default class Cart extends Component {
render() {
return (
<div>
<h3>Hello From Cart</h3>
</div>
)
}
}
The components are displayed using a react router which switches the displayed component depending on the url
class App extends React.Component {
render() {
return (
<React.Fragment>
<NavBar/>
<Switch>
<Route path="/details" Component={Details} />
<Route path="/cart" Component={Cart} />
<Route path="/" Component={ProductList} />
<Route Component={Default} />
</Switch>
</React.Fragment>
);
}
}
Furthermore to avoid confusion, my browser router is encapulating my App component from the index.js
ReactDOM.render(
<Router>
<App />
</Router>
, document.getElementById('root'));
When I navigate to the /cart url on my local host these are my results.
What should be displayed:
https://imgur.com/fZw5QnP.png
However, what is displayed is:
https://i.imgur.com/F1O07Y8.png
Please help me fix this issue, thank you.
I realized my error, I had "Component={}" within the Route, when it was supposed to be "component={}" (lowercase "c"). I'm posting this for all those, who have the same issue.