How properly setup react-router-dom in Home Route? - javascript

I have this index.js:
<Provider store={store}>
<Router history={history}>
<App/>
</Router>
</Provider>
this App.js:
<Switch>
<Route exact path="/" component={Home} />
<Route
path="/login"
render={() => <Login userError={this.state.userError} />}
/>
<Route path="/registration" component={Registration} />;
</Switch>
and Home.js:
<div className="Home">
<Header/>
<div className="content">
<Sidenav/>
<Switch>
<Route path="/friends" component={Friends}/>
</Switch>
<Feed/>
</div>
</div>
I want Friends component to be rendered inside content block, but now if I try to reach /friends route via Link I am getting blank page. If I set /friends Route in App.js, it will be OK, but I won't have it in my content class, because it will be another page.
May you give me a hand with that?
Also in feature I will be have more items to display in content, that's why I put Switch in Home.js
Thanks in advance!

Move your content class and <Friends>
The issue you're having is that the component Home is not rendering when you visit /friends because it will only render when you go to /
To fix this just move the Route into the App.js file, along with the content class into the Friends component.
To make this easier, you could make your content class into a component. This way you could wrap it around all of the stuff you render.
Or move <Friends> and wrap content
What I mean by this is that you could also create your own Route component that wraps whatever component passed to it in a Content component. It might look similar to this:
const ContentRoute = ({ component, ...props }) => (
<Route {...props} component={() => (
<Content>
<component />
</Content>
)}>
</Route>
)

You can access demo here
Here what I have done. This demonstrates how to set layout when page's changing.
- src/
-- components/
--- Header.js
--- Sidenav.js
-- pages/
--- Home.js
--- Login.js
--- withBase.js
-- App.js
-- BaseLayout.js
-- routes.js
At first, let's make dummy components.
components/Header
import React from 'react';
export default () => (
<div>
This is Header.
</div>
);
components/Sidenav
import React from 'react';
export default () => (
<div>
This is Sidenav.
</div>
);
Then, pages.
pages/Home
import React from 'react';
import { NavLink } from 'react-router-dom';
import withBase from './withBase';
const Home = () => (
<div>
<p>Welcome Home!!!</p>
<NavLink to="/login">Go to login page</NavLink>
</div>
);
export default withBase(Home);
pages/Login
import React from 'react';
import { NavLink } from 'react-router-dom';
import withBase from './withBase';
const Login = () => (
<div>
<p>You have to login here...</p>
<NavLink to="/">Go home</NavLink>
</div>
);
export default withBase(Login);
pages/withBase
import React from 'react';
export default WrappedComponent => (
class extends React.Component {
componentDidMount() {
this.props.showHeaderSidenav();
}
render() {
return <WrappedComponent />;
}
}
);
As you see, withBase is a HOC. It runs showHeaderSidenav when the page is mounted.
App
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import BaseLayout from './BaseLayout';
import routes from './routes';
export default class extends React.Component {
state = {
withHeaderSidenav: true
}
showHeaderSidenav = (withHeaderSidenav = true) => {
this.setState({ withHeaderSidenav });
}
render() {
return (
<BaseLayout withHeaderSidenav={this.state.withHeaderSidenav}>
<Switch>
{routes.map(route => (
<Route
exact
key={route.path}
path={route.path}
render={() => (
<route.component
showHeaderSidenav={() => this.showHeaderSidenav(route.withHeaderSidenav)}
/>
)}
/>
))}
</Switch>
</BaseLayout>
);
}
}
BaseLayout
import React from 'react';
import Header from './components/Header';
import Sidenav from './components/Sidenav';
export default ({ withHeaderSidenav, children }) => (
<div>
{withHeaderSidenav && <Header />}
<div className="content">
{withHeaderSidenav && <Sidenav />}
{children}
</div>
</div>
);
We can say that BaseLayout is like a wrapper. It contains dynamic components which will be shown based on withHeaderSidenav prop.
Finally...
routes
import Home from './pages/Home';
import Login from './pages/Login';
export default [
{
path: '/',
component: Home,
withHeaderSidenav: true
},
{
path: '/login',
component: Login,
withHeaderSidenav: false
},
];

You could have moved(declared) content component inside Friends component. I do not see the reason why content component should live outside of Friends component. You can declare content component inside any component that needs it.Content component does not have to mess with routing implementation

Related

How to share the state between all my component?

I currently have an App component, which is the parent to another component "Cart".
I actually use React Router for the routing, and as such my code is :
class App extends Component { // (PARENT)
state = {
likedClass : ["1"]
}
render() {
return (
<Router>
<div className="App">
<Switch>
<Route exact path="/cart" component={() => (<Cart likedClass={this.state.likedClass} /> )}/>
</Switch></div></Router>)} // (etc...)
and a child component (cart)
class Cart extends Component {
render() {
return (
<div className="Cart">
<Header></Header>
<section>
<ul>
{this.props.likedClass.map((course,index) => <CartComponent key={index} ID={course} />)}
</ul>
</section>
<Contact></Contact>
<Footer></Footer>
</div>
)
}
}
export default Cart;
My problem is when I update my state in my App component, my Cart component does not see any change (I change the state with some functions in another children "Course" not shown here for clarity).
I used the React debogger to see that my App state indeed changes when I press the button in my "Course" Children, but still using the React debogger, the state of my Cart never changes and is always showing the initial state..
I am pretty new to React, what am I doing wrong ? Thanks!
Edit :
As asked, the code I use to change the state is in my "course" component, to which I pass a function as a prop, so in my Course component I have :
<button onClick={(e) => {this.props.addLike(course.id)}} className="btn btn-secondary module__button"> LIKER LE COURS</button>
and the function "addLike" is passed through props in the App component as such :
data_cours.map( (card,id) => {
return (<Route exact path={`/${card.categorie}/${card.id}`} key={id} component={() => <Course
id={`${card.id}`}
addLike={this.addLikedClassHandler}
/>} />)
} )
}
may be you missed something. Please check this example. it works perfectly.
App Component
import React, {useEffect, useState} from 'react';
import {BrowserRouter as Router, Switch, Route,} from "react-router-dom";
import history from "./history";
import HelloComponent from "./HelloComponent";
class App extends React.Component {
state = {
likedClass: ["khabir"]
};
render() {
return (
<div>
<Router history={history}>
<Switch>
<Route exact path="/hello"
component={() => (<HelloComponent likedClass={this.state.likedClass} />)}/>
</Switch>
</Router>
</div>
)
}
}
export default App;
history.js
import {createBrowserHistory} from "history";
export default createBrowserHistory();
Hello Component
import React from "react";
export default function HelloComponent({likedClass}) {
return (
<div>
<ul>
{likedClass}
</ul>
</div>
);
}

React-router v4, URL changing but component doesn't render

I've tried everything but fail to render component when URL changes. No error messages nothing, react-redux is installed but not using it yet, so it can't be the problem. When I check it from to Google chrome React dev tools, nothing happens, there is no match, history vs anything. I couldn't find a solution, is there any way to make it work?
https://codesandbox.io/s/vm3x9n4k67
Here is my NavBar.js. I import NavLink from react-router-dom and implement these
import React from 'react'
import classes from "./NavBar.css";
import { NavLink } from 'react-router-dom';
const NavBar = (props) => {
return (
<div className={classes.NavBar}>
<h1 className={classes.NavBar_list} >foodbase</h1>
<ul className={classes.NavBar_list}>
<NavLink to="/auth"> <li className={classes.NavBar_list_item}>Signin</li></NavLink>
<NavLink to="/"><li className={classes.NavBar_list_item}>Main Page</li></NavLink>
</ul>
</div>
)
}
export default NavBar
this is my Layout.js render property:
render() {
let recipes = [];
if (this.state.recipes.length > 0) {
recipes = this.state.recipes;
}
return (
<div>
<NavBar/>
<SearchBox
onChangeHandler={this.onChangeHandler}
value={this.state.inputValue}
onSearchClick={this.onClickedHandler} />
<section className={classes.SearchSection}>
<ul className={classes.SearchResultArea}>
<SearchResults
Results={recipes}
></SearchResults>
</ul>
</section>
</div>
)
}
and finally app.js:
import React, { Component } from 'react';
import { Switch, Route, BrowserRouter, withRouter } from 'react-router-dom';
import Auth from './components/Auth/Auth';
import SearchBox from './components/SearchBox/SearchBox';
import Layout from './containers/Layout/Layout';
import './App.css';
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<Switch>
<Layout>
<Route path="/auth" component={Auth} />
<Route path="/" exact component={SearchBox} />
</Layout>
</Switch>
</BrowserRouter>
</div>
);
}
}
export default withRouter(App);
I assume that you need to put your Route components directly into Switch and don't forget to render children in Layout. So try this:
app.js:
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<Layout>
<Switch>
<Route path="/auth" component={Auth} />
<Route path="/" exact component={SearchBox} />
</Switch>
</Layout>
</BrowserRouter>
</div>
);
}
}
Layout.js
render() {
// ...
return (
<div>
<NavBar />
{ this.props.children } // <-- your route specific components
</div>
)
}

React Router Error: You should not use Route outside of Router

I'm just doing some basic routing in my react app and I've done it this way before so I'm pretty confused to as why it isn't working now.
The error I am getting says: You should not use <Route> or withRouter() outside a <Router>
I'm sure this is super basic so thanks for baring with me!
import React from 'react'
import { Route } from 'react-router-dom'
import { Link } from 'react-router-dom'
import * as BooksAPI from './BooksAPI'
import BookList from './BookList'
import './App.css'
class BooksApp extends React.Component {
state = {
books: []
}
componentDidMount() {
this.getBooks()
}
getBooks = () => {
BooksAPI.getAll().then(data => {
this.setState({
books: data
})
})
}
render() {
return (
<div className="App">
<Route exact path="/" render={() => (
<BookList
books={this.state.books}
/>
)}/>
</div>
)
}
}
export default BooksApp
You need to setup context provider for react-router
import { BrowserRouter, Route, Link } from 'react-router-dom';
// ....
render() {
return (
<BrowserRouter>
<div className="App">
<Route exact path="/" render={() => (
<BookList
books={this.state.books}
/>
)}/>
</div>
</BrowserRouter>
)
}
Side note - BrowserRouter should be placed at the top level of your application and have only a single child.
I was facing the exact same issue. Turns out that i didn't wrap the App inside BrowserRouter before using the Route in App.js.
Here is how i fixed in index.js.
import {BrowserRouter} from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
document.getElementById('root')
);

React Component not rendering on using react router 4

I am working on a simple demo React project. I have a Home component which gets rendered when directly placed in main.js but when placed inside the Router in Routes.js, it is not rendered. Can anyone let me know what am I doing wrong here?
main.js file
import React from "react";
import {render} from "react-dom";
import {App} from "./app/App";
import Routes from "./app/Routes";
render( <Routes />,
document.getElementById("root")
)
Routes.js file
import React from "react";
import {
BrowserRouter as Router,
Route,
Switch,
} from "react-router-dom";
import {App}
from "./App";
import Home from "./components/Home";
export default function Routes(props) {
console.log('Routes');
return (
<Router>
<App>
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</App>
</Router>
)
}
App.js file
import React from "react";
import Header from "./components/Header";
export class App extends React.Component {
render() {
console.log("App render");
return (
<div>
<h1> Welcome to React </h1>
<Header/>
</div>
)
}
}
Header.js file
import React, {Component} from 'react';
import {NavLink} from 'react-router-dom';
export default class Header extends Component {
render() {
console.log("Header render");
return (
<div>
<NavLink to="/" exact>
Home
</NavLink>
</div>
)
}
}
Home.js file
import React, {Component} from "react";
export default class Home extends Component {
render() {
console.log("Home render");
return (
<div>
<h2>Hello World!</h2>
</div>
)
}
}
This is because you are using App component as the wrapper of whole app, and defined the Switch as the children of App component, so you need to use this.props.children inside App.
Like this:
export class App extends React.Component {
render() {
console.log("App render");
return (
<div>
<h1> Welcome to React </h1>
<Header/>
{this.props.children}
</div>
)
}
}
Consider this example to make the whole picture more clear, if you write:
<App>
<Home />
</App>
Means Home will get passed as children to App component, automatically it will not get rendered inside App, you need to put this.props.children somewhere inside App.
With react-router-v4 which you seem to be using, it is possible to have dynamic Routing which means you can add the Routes within nested components and hence apart from the solution that #MayankShukla suggested you could also keep the <Switch> and other routes within App like
export default function Routes(props) {
console.log('Routes');
return (
<Router>
<App/>
</Router>
)
}
export class App extends React.Component {
render() {
console.log("App render");
return (
<div>
<h1> Welcome to React </h1>
<Header/>
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</div>
)
}
}
You could read more about the advantages of Dynamic Routing here

React Router Component not Rendering

I've been working with React Router and trying to route my App.js and Car.js components together. I wrote {this.props.children} in those two components but it still isn't working. There is no where on my local host page that shows any indication of the Car.js component when I deploy my app.
Here's my App.js:
import React, { Component } from 'react';
import Login from './Login.js';
import Search from './Search.js';
import Message from './Message.js';
import Car from './Car.js';
import {BrowserRouter, Route} from 'react-router-dom';
export default class App extends React.Component {
render() {
return (
<div>
<Login />
<Search />
<Message />
<div>
<BrowserRouter>
<Route path="/Car" component={Car}/>
</BrowserRouter>
{this.props.children}
</div>
</div>
);
}
}
Car.js:
// Car page example
import React, { Component } from 'react';
import {Router, Route} from 'react-router';
class Car extends Component {
render(){
return(
<div>
<h1> Cars page </h1>
{this.props.children}
</div>
);
}
}
export default Car;
So you're going to want at least 2 routes unless /Cars is the only page in which case you don't need routing! :)
In this example the Home component will be displayed when your url is something like http:/www.exmaple.com/
The Cars component will be displayed when the url is http:/www.exmaple.com/Cars
const App = () => (
<div>
<Login />
<Search />
<Message />
<div>
<BrowserRouter>
// you're going to want a default view
<Route exact path="/" component={Home} />
// this will be displayed when your url has /Car at the end of it
<Route path="/Car" component={Car} />
</BrowserRouter>
</div>
</div>
);
If you don't want to have to manually type in the urls to change the views... You will have to include a <Link /> or a <NavLink /> that points to the respective view.
Try <NavLink to="/Cars" /> and don't forget to add { ... NavLink ... } from "react-router-dom" as well.
You might want to have a look at react-router WEB documentation over at ReactTraining.com's react-router page. They're the people who created and maintain react-router. Good documentation as well!

Categories