I have my meteor app working with React and React-Router. I am able to set up routes and render them correctly. My issue is I would like to render a component inside a layout (common grid, menu, header, etc). Right now, any path renders the components by taking over the entire page.
main.html
<head>
<title>List App</title>
</head>
<body>
<div id="target"></div>
</body>
main.coffee
browserHistory = createBrowserHistory()
export renderRoutes = () => (
<Router history={browserHistory}>
<Switch>
<Route exact path='/' component={App} />
<Route path="/mylists" component={MyLists} />
<Route path="/list/:listId" component={List} />
<Route path="/layout" component={Layout} />
<Route exact path="/discover" component={Browse} />
<Route component={NotFoundPage} />
</Switch>
</Router>
)
Meteor.startup () ->
console.log "Hello from Client."
render(renderRoutes(), document.getElementById('target'))
When the browser navigates to a route (ie. path=’/’) then the browser displays ONLY that single component, in this case, App. Makes perfect sense as I am rendering all the routes to target.
I am trying to get a route to render INSIDE another component. For example, I want a layout component with nav, logo, etc. Once a user hit’s a route, I’d want just that component rendered inside the layout (ie. MyLists, Browse, etc). Seems like it should be straightforward, but I can’t seem to get set it up right.
Appreciate any advice.
So this is really not a meteor question but a react-router question, and it depends on which version of RR you’re using. If it’s RR V4, you can do it like so:
// Just to make sure you're importing BrowserRouter
import { BrowserRouter, Route, Switch } from "react-router-dom";
...
<BrowserRouter>
<div>
<Header />
<Menu />
// ... other constantly shown components
// then, put your route specific components inside the switch:
<Switch>
<Route exact path='/' component={App} />
<Route path="/mylists" component={MyLists} />
<Route path="/list/:listId" component={List} />
<Route path="/layout" component={Layout} />
<Route exact path="/discover" component={Browse} />
<Route component={NotFoundPage} />
</Switch>
</div>
</BrowserRouter>
Based on how you have it set up though I think you might be using V3. If you are, I would recommend upgrading. If you really don’t want to, you can make it work like this
const App = props => (
<div>
<Header />
<Menu />
// ... other constantly shown components
{props.children} // route-specific components will appear here
</div>
);
// and then modify your renderRoutes to be like:
export renderRoutes = () => (
<Router history={browserHistory}>
<Switch>
<Route path='/' component={App} /> // this uses the App component we made above. All below components will appear there as `props.children` when their route is selected
<IndexRoute component={IndexRouteComponent} /> // The component to send to App's `props.children` when route is '/'
<Route path="/mylists" component={MyLists} />
<Route path="/list/:listId" component={List} />
<Route path="/layout" component={Layout} />
<Route exact path="/discover" component={Browse} />
<Route component={NotFoundPage} />
</Switch>
</Router>
)
1 Like
I’m on RR4, so this worked great. Thanks for the help!!
Also, RR4 render function allows you to render whatever you want within a route including logic to determine that: https://reacttraining.com/react-router/web/api/Route/render-func
Thanks to everyone for the replies. Apologies for my novice React Router questions, but I think I am close.
I have the layout showing up correctly, but the navigation, when clicked, changes the browser bar location address, but does not reload the content. In essence, I can click around my and the links change to active color (provided by antD), but the content won’t change unless I reload the page manually.
export renderRoutes = () => (
<div>
<Layout className="layout">
<Header style={{ position: 'fixed', zIndex: 1, width: '100%' }}>
<div className="logo">
<img width={125} height={40} alt="logo" src="../imports/images/logo.png" />
</div>
<BrowserRouter>
<NavBar />
</BrowserRouter>
</Header>
<Content style={{ padding: '0 50px' }}>
<div style={{ background: '#fff', padding: 24, minHeight: 768 }}>
<BrowserRouter>
<div>
<Switch>
<Route exact path='/' component={App} />
<Route path="/mylists" component={MyLists} />
<Route path="/list/:listId" component={List} />
<Route path="/layout" component={Layout} />
<Route exact path="/discover" component={Browse} />
<Route component={NotFoundPage} />
</Switch>
</div>
</BrowserRouter>
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>
BetterList // ©2018
</Footer>
</Layout>
</div>
)
Meteor.startup () ->
console.log "Hello from Client."
render(renderRoutes(), document.getElementById('target'))
My NavBar component is…
export default class NavBar extends Component
render: () ->
(<Menu
mode="horizontal"
defaultSelectedKeys={['1']}
style={{ lineHeight: '48px' }}
>
<Menu.Item key="1"><Link to="/">Home</Link></Menu.Item>
<Menu.Item key="2"><Link to="/discover">Discover</Link></Menu.Item>
<Menu.Item key="3"><Link to="/mylists">My Lists</Link></Menu.Item>
</Menu>
)
Try getting rid of the two <BrowserRouter>
s that you have and replace the outermost <div>
with a <BrowserRouter>
1 Like