netizen0911
netizen0911

Reputation: 461

Excluding <Header /> component on a specific page with react-router

Here's a working code:

const AppRouter = () => (
<BrowserRouter>
  <div>
    <Header />
    <Switch>
      <Route path="/" component={DashboardPage} exact={true} />
      <Route path="/:id" component={ViewerPage} /> // <-- Exclude Header component from this page
      <Route path="/create" component={CreatePage} />
      <Route path="/edit/:id" component={EditPage} />
      <Route path="/help" component={HelpPage} />
      <Route component={NotFoundPage} />
    </Switch>
  </div>
</BrowserRouter>
);

export default AppRouter;

I couldn't seem to figure out how to exclude the Header component from ViewerPage component page. Is there any way to do this?

Upvotes: 9

Views: 11689

Answers (4)

Jay
Jay

Reputation: 179

In your Router file call useRouteMatch() before a <Switch>

export Routes = (
{useRouteMatch("/specific-route")?.isExact ? (
          <Header />
        ) : null}

<Switch>
  <Route path="other/path" component={Other}
  ...
</Switch>
);

Alternatively, call withRouter() to have direct access to match, location and history.

export const AuthenticatedRoutes = withRouter(() => (
  {location.pathname !== `/special-url` ? (
    <Header />
  ) : null}

  <Route path="/special-url" component={Special}
  <Route path="/other" component={Other} 
));

export Routes = (
  {useRouteMatch("/specific-route")?.isExact ? (
    <Header />
  ) : null}
            
  <Switch>
    <Route component={AuthenticatedRoutes}          
  </Switch>
);
     

Upvotes: 0

varoons
varoons

Reputation: 3887

Had the exact same requirement in my last project and I went with the approach of splitting the header out into its own component and the using React Fragments. Idiomatic!

import React, { Fragment } from 'react'
// ...

const App = () => (
  <div>
    <Switch>
      <Route path='/no-header-route' component={NoHeaderComponent} />   // Route without header
      <Fragment>            // This is the key
        <Header/>           // Header is in its own component
        <Route path='/route-1' component={Comp1}/>  // Route with header
        <Route path='/route-2' component={Comp2}/>  // Route with header
      </Fragment>
    </Switch>
  </div>
)

Upvotes: 22

Kyle Richardson
Kyle Richardson

Reputation: 5645

The withRouter Higher-order-Component provided by the react-router package will give you access to the location object. Once you have that you can conditionally render the header by short-circuiting.

import {withRouter} from 'react-router'

const App = ({location}) => (
  <div>
    {location.pathname !== '/exclusion-path' && <Header/>}
    <Switch>
      ...
    </Switch>
  </div>
)

export default withRouter(App)

or to exclude on multiple paths...

const exclusionArray = [
  '/path-one',
  '/another-path',
]

const App = ({location}) => (
  <div>
    {exclusionArray.indexOf(location.pathname) < 0 && <Header/>}
    <Switch>
      ...
    </Switch>
  </div>
)

If you're doing anything serious I'd recommend using the context api and short-circuit on a value provided by context. If this is the case and you need some direction I'd be happy to explain it to you.

P.S. If you want to do it with the alpha Hooks API I'll get really excited.

EDIT: To address commont.

Move your Router outside of the App component.

import {BrowserRouter as Router} from 'react-router-dom'
import ReactDOM from 'react-dom'

ReactDOM.render(
  <Router>
    <App/>
  </Router>,
  document.getElementById('render-target')
)

Upvotes: 11

arikanmstf
arikanmstf

Reputation: 473

1- something like, In Header.js

  import {withRouter} from 'react-router-dom';

        class Header extends Component {
          render() {
            if (this.props.location.pathname === '/') {
              return null
            }
            return (
              // other stuff
            );
          }
        }
  export default withRouter(Header);

Note that, withRouter can be different with different react router version. But idea is the same: check your pathname with ViewerPage's pathname, and do not display Header if it is the path...

2- Other approach is do the same thing with 'redux'

so whenever ViewerPage is loaded, dispatch an action. In ViewerPage.js

class ViewerPage extends Component {
          componentDidMount() {
            this.props.updateShouldDisplayHeader(false);
          }
          componentWillUnmount(){
             this.props.updateShouldDisplayHeader(true);
           }
        }

In Header.js

class Header extends Component {
          render() {
            if(!this.props.shouldDisplayHeader) {
               return null;
            }
            return (
              // other stuff
            );
          }
        }

I suppose you already know how to create action and use reducers on redux

Upvotes: 0

Related Questions