Nikita Shchypyplov
Nikita Shchypyplov

Reputation: 1160

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

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!

Upvotes: 4

Views: 858

Answers (3)

Andria
Andria

Reputation: 5085

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>
)

Upvotes: 4

Ukasha
Ukasha

Reputation: 2334

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
  },
];

Upvotes: 3

Serdar
Serdar

Reputation: 478

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

Upvotes: 0

Related Questions