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>
)
}
}
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
The functions onEnter and onUpdate, does not work on react 4. I try different way to listen to this change but I start to turn in circles.
I would like to manage everything in my App component.
This function would allow me to close my Menu at each change of course. (isOpen) ==> False
Git of this project: https://github.com/marcdubois71450/Library-Exercise
I use react-router-dom, and react 4
import React, {Component} from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import PropTypes from 'prop-types';
import { scaleDown as Menu } from 'react-burger-menu'
import './App.css';
import Navigation from '../Navigation';
import LandingPage from '../Landing';
import SignUpPage from '../SignUp';
import SignInPage from '../SignIn';
import PasswordForgetPage from '../PasswordForget';
import HomePage from '../Home';
import AccountPage from '../Account';
import AdminPage from '../Admin';
import * as ROUTES from '../../constants/routes';
export default class App extends Component {
render() {
return (
<Router>
<div>
<Menu pageWrapId={ "page-wrap" } outerContainerId={ "outer-container" } isOpen={this.isOpen} >
<Navigation />
</Menu>
<main id="page-wrap">
<Route exact path={ROUTES.LANDING} component={LandingPage} />
<Route path={ROUTES.SIGN_UP} onEnter={this.onChangeRoute} component={SignUpPage} />
<Route path={ROUTES.SIGN_IN} onEnter={this.onChangeRoute} component={SignInPage} />
<Route path={ROUTES.PASSWORD_FORGET} onEnter={this.onChangeRoute} component={PasswordForgetPage} />
<Route path={ROUTES.HOME} onEnter={this.onChangeRoute} component={HomePage} />
<Route path={ROUTES.ACCOUNT} onEnter={this.onChangeRoute} component={AccountPage} />
<Route path={ROUTES.ADMIN} onEnter={this.onChangeRoute} component={AdminPage} />
</main>
</div>
</Router>
);
}
}
I would like to manage everything in my App component.
Use render instead of onEnter in React Router V4
Exemple from the doc:
// convenient inline rendering
<Route path="/home" render={() => <div>Home</div>}/>
// wrapping/composing
const FadingRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
<FadeIn>
<Component {...props}/>
</FadeIn>
)}/>
)
<FadingRoute path="/cool" component={Something}/>
Render Function
I am trying to access my store from every component page I have, so I followed the following tutorial in order to connect React Router & MobX.
http://frontendinsights.com/connect-mobx-react-router/
However, I am facing a problem at The MobX way – Provider component.
This is the code exmaple:
import { Provider } from 'mobx-react';
import usersStore from './stores/usersStore';
import itemsStore from './stores/itemsStore';
const stores = { usersStore, itemsStore };
ReactDOM.render(
<Provider {...stores}>
<Router history={history}>
<Route path="/" component={App}>
</Route>
</Router>
</Provider>,
document.getElementById('app')
);
I tried to do the same in index.js
import React from 'react'
import { render } from 'react-dom'
import { Router, hashHistory, Route, IndexRedirect } from 'react-router'
import App from './webapp/App'
import Home from './components/pages/Home'
import Dogs from './components/pages/Dogs'
import Cats from './components/pages/Cats'
import Provider from 'mobx-react'
import RootStore from './webapp/stores'
const store = RootStore
render((
<Provider rootStore={store}>
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRedirect to="/home" />
<Route path="/home" component={Home}/>
<Route path="/dogs" component={Dogs}/>
<Route path="/cats" component={Cats}/>
</Route>
</Router>
</Provider>
), document.getElementById('app'))
However, because of <Provider/>, I am getting an error:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
Why am I getting that? It should work doesn't it?
Thanks for any help !
If it's a web app, react-router-dom should be used.
Here is the correct way to inject store with Provider https://github.com/mobxjs/mobx-react#observer
I wrote a solution for your code without using decorator, so it supports create-react-app:
import React, { Component } from 'react';
import { Provider, Observer } from 'mobx-react';
import { observable } from 'mobx';
import { BrowserRouter, Switch, Route, Link, Redirect } from 'react-router-dom';
const myStore = observable({
home: 'Home',
cat: 'Cat',
});
const Home = () => (
<Observer
inject={stores => ({ myStore : stores.myStore })}
render={props => (<section><h1>{props.myStore.home}</h1></section>)}
/>
);
const Cat = () => (
<Observer
inject={stores => ({ myStore : stores.myStore })}
render={props => (<section><h1>{props.myStore.cat}</h1></section>)}
/>
);
class App extends Component {
render() {
return (
<BrowserRouter>
<Provider myStore={myStore}>
<div className="App">
<header className="App-header">
<nav>
<ul>
<li><Link to="/home">HOME</Link></li>
<li><Link to="/cat">CAT</Link></li>
</ul>
</nav>
</header>
<Switch>
<Route path='/home' exact component={Home} />
<Route path='/cat' exact component={Cat} />
<Redirect from="/" to="/home" />
</Switch>
</div>
</Provider>
</BrowserRouter>
);
}
}
export default App;
All the components are in App.js file. There is no change in default index.js from create-react-app.
Note:
The another way to doing this, it's to simply create a singleton class for the store and use export default new Store() to make it available to all components. The class itself doesn't have to be observable, but its properties do.
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