I've recently started using React for a project I'm working on and had a quick question.
I have a few page components I've created but want each one to have the same Header - currently their render() functions look like:
return (
<div>
<Header />
... {{ page specific elements here }}
</div>
)
I was wondering if there is a way I can set elements that I want on every page (i.e. the header) to be consistent without manually inserting them into the render function of each component?
My main.js file is:
import Header from './components/Header'
import history from './history'
import React from 'react'
import ReactDOM from 'react-dom'
import { Link, Route, Router, Switch } from 'react-router-dom'
import Discover from './pages/Discover';
import Layout from './pages/Layout';
import Search from './pages/Search';
const app = document.getElementById('app')
ReactDOM.render(
<Router history={history}>
<Switch>
<Route exact path='/' component={Layout}/>
<Route path='/discover' component={Discover}/>
<Route path='/search' component={Search}/>
</Switch>
</Router>,
app
)
And my index.html page:
<body>
<div>
<div class="row">
<div class="col-lg-12">
<div id="app"></div>
</div>
</div>
</div>
<script src="client.min.js"></script>
</body>
If you want the header to be consistently rendered across all routes inside the router, then just add Header component inside the router.
import Header from './components/Header'
import history from './history'
import React from 'react'
import ReactDOM from 'react-dom'
import { Link, Route, Router, Switch } from 'react-router-dom'
import Discover from './pages/Discover';
import Layout from './pages/Layout';
import Search from './pages/Search';
const app = document.getElementById('app')
ReactDOM.render(
<Router history={history}>
<Header/> {//Just put it in here}
<Switch>
<Route exact path='/' component={Layout}/>
<Route path='/discover' component={Discover}/>
<Route path='/search' component={Search}/>
</Switch>
</Router>,
app
)
If you want to avoid it showing up in a particular route like may be login, you can render login in main.js routes and then take the Switch to an inner Route.
ReactDOM.render(
<Router history={history}>
<Route exact path='/login' component={Login}/>
<Route path='/' component={App}/>
</Router>,
app
)
and then in the inner Route:
<div>
<Header/> {//Just put it in here}
<Switch>
<Route exact path='/' component={Layout}/>
<Route path='/discover' component={Discover}/>
<Route path='/search' component={Search}/>
</Switch>
</div>
You can do it with React Higher-Order Component
like this:
function withLayout(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Header /> // header or any thing
<WrappedComponent {...this.props} />
</div>
)
}
};
}
and in your page containers (example: Discover):
class Discover extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
blah blah .... I am discover page
</div>
)
}
};
const discoverWithLayout = withLayout(Discover)
export default discoverWithLayout
Related
I'm creating a Google Clone. This is my current code for that. I read that I needed to changed the syntax from 'Switch' to 'Routes', given the update for react-router. I did just that and my "This is the search page" is not displaying inside of the browser.
import React from "react";
import './App.css';
import Home from './pages/Home';
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"
function App() {
return (
// BEM
<div className="app">
<Router>
<Routes>
<Route path="/search">
<h1>This is the search page</h1>
</Route>
<Route path="/">
<Home />
</Route>
</Routes>
</Router>
</div>
);
}
export default App;
you need to create each component speratly some things like this:
import React from 'react;
function Home(){
return(
<div>
<h1>Home</h1>
</div>
);
}
export default Home;
import React from 'react;
function Search(){
return(
<div>
<h1>Search</h1>
</div>
);
}
export default Search;
change index.js to :
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById("root"));
change App.js to
import React, {useEffect} from 'react';
import ReactDOM from "react-dom";
import { BrowserRouter ,Routes,Route} from 'react-router-dom';
import Search from '.........'
import Home from '.......'
function App(){
return(
<BrowserRouter>
<Routes>
<Route exact path="/" element={<Home/>} />
<Route path="/search" element={<Search/>} />
<Routes>
</BrowserRouter>
);
}
export default App;
if(document.getElementById('app')){
ReactDOM.render(<App/>,document.getElementById('app'));
}
In react-router-dom#6 the Routecomponent API changed significantly. Thechildrenprop is only used for rendering nestedRoutecomponents. All routed content is now rendered on a singleelementprop taking aReactNode`, a.k.a. JSX.
Move the content from being wrapped into the element prop.
function App() {
return (
// BEM
<div className="app">
<Router>
<Routes>
<Route path="/search" element={<h1>This is the search page</h1>} />
<Route path="/" element={<Home />} />
</Routes>
</Router>
</div>
);
}
Route component expects 2 parameters path, and element.
Refer to the official doc here
function App() {
return(
<BrowserRouter>
<Routes>
<Route path="/" element={<Home/>} />
<Route path="/search" element={<Search/>} />
<Routes>
</BrowserRouter>
);
}
I am new to React and practicing with an online website for repairing appliances. I have used react-router and created all my routes in a separate file.
I have a problem though, I can open any link from the address bar like:
http://localhost:3000/<randomword>
I only want routes to be opened that I have declared in my routes component while if I type http://localhost:3000/something, I get an empty page with my header and footer in it.
here are my codes:
Index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import Routes from './Routes';
import './index.css';
const App = () => {
return(
<BrowserRouter>
<Routes />
</BrowserRouter>
)
}
ReactDOM.render(<App/>,document.getElementById('root'));
App.js:
import React, {Component} from 'react';
import { Route, BrowserRouter } from 'react-router-dom';
import Layout from './Containers/Layout';
import LandingPage from './Containers/Pages/LandingPage';
import About from './Containers/Pages/About';
import Cities from './Containers/Pages/Cities';
import Discount from './Containers/Pages/Discount';
class Routes extends Component {
render(){
return (
<div>
<Layout>
<BrowserRouter>
<Route path="/" render={props => <LandingPage {...props} />} exact component={LandingPage}/>
<Route path="/About" component={About}/>
<Route path="/Cities" component={Cities}/>
<Route path="/Discount" component={Discount}/>
</BrowserRouter>
</Layout>
</div>
);
}
};
export default Routes;
Layout.js:
import React, { Component } from 'react';
import Header from "./Layouts/Header";
import Footer from './Layouts/Footer';
import './Layout.css';
export default class Layout extends Component {
constructor(){
super();
this.state= {
}
}
render() {
return (
<div className="page-container">
<Header/>
<div className="content-wrap">
{this.props.children}
</div>
<Footer/>
</div>);
}
}
Can someone help me figure out how I should stop random random pages to be opened from addressbar?
Just want to start by saying I'm completely self-taught with React so I apologize if this answer is incorrect. However, in my experience with react-router I always have a Switch inside of my BrowserRouter. So your Routes class in app.js should something like this:
class Routes extends Component {
render(){
return (
<div>
<Layout>
<BrowserRouter>
<Switch>
<Route path="/" render={props => <LandingPage {...props} />} exact component={LandingPage}/>
<Route path="/About" component={About}/>
<Route path="/Cities" component={Cities}/>
<Route path="/Discount" component={Discount}/>
</Switch>
</BrowserRouter>
</Layout>
</div>
);
}
};
Just be sure you don't forget to update your imports to
import { Switch, Route, BrowserRouter } from 'react-router-dom';
import { Redirect } from "react-router-dom"
<Route path="/not-found" component={notFound-Component} />
<Redirect to="/not-found" />
This will always redirect you to 404 component if route is not present just make a 404 component and u should add the redirect at the end after all routes are defined
I'm starting in React and I'm curious about about if have any way to change a page without reload all the html, changing only a content component for example.
I know that there is a way to change the component without change the url but I thought that if the url change too the application would be better.
React Router is the exact thing you're looking for
Here, how you can achieve what you're looking for.
First, wrap your app with BrowserRouter
import { BrowserRouter } from "react-router-dom";
import React from 'react';
class App extends React.Component {
return (){
return (
<BrowserRouter>
<SomeComponent />
</BrowserRouter>
)
}
}
Now just use the Route and Link. Route told the application which component to render on the basis of the current route and Link changes the URL without reloading the whole page
import { Route, Link, Switch } from "react-router-dom";
import React from 'react';
import {Circle, Square} from './someFileWithComponents';
class SomeComponent extends React.Component {
render(){
return (
<div>
<Link to='/circle' >Circle</Link>
<Link to='/square' >Square</Link>
<Switch>
<Route path='/circle' component={Circle} />
<Route path='/square' component={Square} />
</Switch>
</div>
)
}
}
React Router is what you looking for
const AppRouter =()=>(
<BrowserRouter>
<div>
<Header/>//where Header components contains the navigation
<Switch>
<Route path="/" component={BookListPage} exact={true} />
<Route path="/create" component={AddBookItem} />
<Route path="/edit/:id" component={EditBookItem} />
<Route path="/help" component={HelpPage} />
<Route component={NotFoundPage} />
</Switch>
</div>
</BrowserRouter>
);
export default AppRouter;
I am following a course where the author has written some code for routing in react using react-router version 3.
<Router history={browserHistory} >
<Route path="/" component={Main}>
<IndexRoute component={PhotoGrid}></IndexRoute>
<Route path="/view/:postId" component={Single}>
</Route>
</Router>
While following the course(in which I am using using router version 4), I came to know that now the <IndexRoute> doesn't exists. I googled for alternative and found that exact is the alternative. But I don't know how to use exact for meeting this requirement. The author want the Main component always on the DOM, and based on the url only the child components should change(i.e Single or PhotoGrid).
I tried below code, which is of course the wrong one:
<BrowserRouter>
<Switch>
<Route path="/" component={Main} />
<Route exact path="/" component={PhotoGrid} />
<Route path="/veiw/:postId" component={Single} />
</Switch>
</BrowserRouter>
My components are:
class Main extends React.Component {
render() {
return (
<div>
<h1>
<Link to="/">Reduxtagram</Link>
</h1>
{React.cloneElement(this.props.children, this.props)}
</div>
);
}
}
class PhotoGrid extends React.Component {
render() {
return <div className="photo-grid">PhotoGrid</div>;
}
}
class Single extends React.Component {
render() {
return <div className="single-photo">Single</div>;
}
}
The Switch component will only render the first Route that is a match.
You could use the Main component as a regular component and use the Switch as children for that.
<BrowserRouter>
<Main>
<Switch>
<Route exact path="/" component={PhotoGrid} />
<Route path="/view/:postId" component={Single} />
</Switch>
</Main>
</BrowserRouter>
i know this is an old question but im following the same course and i decided to update all the libraries, basically i had to restructure the app like this:
reduxtagram.js :
import React from 'react';
import {render} from 'react-dom';
import App from './components/App';
import {Provider} from 'react-redux';
import store from './store';
// import css
import css from './styles/style.styl';
// import react router deps
const router = (
<Provider store={store}>
<App/>
</Provider>
)
render(router , document.getElementById('root'));
main.js:
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import PhotoGrid from './PhotoGrid';
import Single from './Single';
import {Router, Route} from 'react-router-dom';
import {history} from '../store';
export default class Main extends Component {
render() {
return (
<div>
<Router history={history}>
<Route
path="/"
render={(routeProps) => (
<h1>
<Link to='/'>Reduxstagram </Link>
</h1>
)}/>
<Route
path="/grid"
render={(routeProps) => (
<PhotoGrid {...routeProps} {...this.props} />
)}/>
<Route
path="/grid/view/:postID"
render={(routeProps) => (
<Single {...routeProps} {...this.props} />
)}/>
</Router>
</div>
)
}
}
I have Header and Footer components, which are used for surrounding internal pages.
I also have a Login component, which appears when the user is not logged in. This component doesn't implement Header or Footer components.
The problem is that I can't prevent Header and Footer components from being rendered with Login component. I can't exclude Login component to be rendered alone.
I tried Switch tag, but didn't get it to work.
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import { connect } from 'react-redux';
import * as actions from '../actions';
import Header from "./Header";
import Footer from "./Footer";
import Login from "./Login";
import manageCategories from "./manageCategories";
class App extends Component {
componentDidMount() {
this.props.fetchUser();
}
render() {
return (
<div>
<BrowserRouter>
<div>
<Route exact path="/login" component={Login} />
<Header />
<Route exact path="/manage-categories" component={manageCategories} />
<Footer />
</div>
</BrowserRouter>
</div>
);
}
}
export default connect(null, actions)(App);
You should add a new component that is parallel to the login component to contain the Header and Footer components.
<Route path="/home" component={Layout}/>
<Route exact path="/login" component={Login}/>
and the Layout:
render() {
return <div>
<Header />
<Route exact path={this.props.match.path} component={Home} />
<Route path={`${this.props.match.path}/manageCategories`} component={manageCategories} />
<Route path={`${this.props.match.path}/other`} component={otherComponent} />
<Footer />
</div>
}