Adding multiple routes with react-router in an electrode app does nothing - reactjs

I'm getting started with Walmart's react/redux/react-router/isomorphic boilerplate called electrode and I'm having trouble adding multiple routes. When I add the 2nd route it seems to do nothing and linking and pushing to the other routes does not change the page.
http://www.electrode.io/docs/get_started.html
https://github.com/electrode-io/electrode-redux-router-engine
Here's what the single route in the boilerplate looked like
// routes.jsx
import React from "react";
import {Route} from "react-router";
import Home from "./components/home";
export const routes = (
<Route path="/" component={Home}/>
);
and here's what I changed it to
import React from "react";
import {Route, IndexRoute} from "react-router";
import Home from "./components/home";
import Foo from "./components/foo";
export const routes = (
<Route path="/" component={Home}>
<Route path="/foo" component={Foo}/>
</Route>
);
I couldn't put the routes side by side because that gave me an error saying that jsx can't have two elements side-by-side so I had to nest it. The react router examples I see online seem to assume a root app component. Looking at the electrode router redux sample, they set the root component to "Page". What is the "Page" component? My questions are
Why doesn't my 2nd route work?
Should I be using an IndexRoute?
Do I need to create a root component for the root route? If so what does that component look like?
Here's the app.jsx code
//
// This is the client side entry point for the React app.
//
import React from "react";
import {render} from "react-dom";
import {routes} from "./routes";
import {Router} from "react-router";
import {createStore} from "redux";
import {Provider} from "react-redux";
import "./styles/base.css";
import rootReducer from "./reducers";
//
// Add the client app start up code to a function as window.webappStart.
// The webapp's full HTML will check and call it once the js-content
// DOM is created.
//
window.webappStart = () => {
const initialState = window.__PRELOADED_STATE__;
const store = createStore(rootReducer, initialState);
render(
<Provider store={store}>
<Router>{routes}</Router>
</Provider>,
document.querySelector(".js-content")
);
};

A few things...
You can avoid the "side by side jsx" warning by wrapping your routes in an empty route or returning an array.
// return nested routes
return (
<Route path="/">
<Route path="foo" component={Foo}/>
<Route path="bar" component={Bar}/>
</Route>
)
// return array, must use keys
return [
<Route key="foo" path="/foo" component={Foo}/>,
<Route key="bar" path="/bar" component={Bar}/>
]
If you want to nest routes, you need to give way to the child component by adding {this.props.children} to the parent component's render.
If you want truly separate routes that are not nested, it shouldn't be a child of the first route. I don't think adding an IndexRoute would provide any benefit unless you want some UI that is top level for all routes (like rendering a header, sidebar, etc).

Related

Where to set up react router tags?

I've read some answers here and it seems they are all replying to a specific problem. Mine more about usage and placement rather than a problem I am facing. I also read the documentation but it does not answer my question.
My question is where to use react-router components?
Do I import (and use) BrowserRouter in index.js or App.js or does it go wherever the navigation bar is?
Do Route, Switch, NavLink, Link must be in the same module/file? If not, do I use them around the navigation bar element?
On the official website it shows that <Switch> is INCLUDED within <BrowserRouter> tags AFTER <Link> elements were used. Can I conclude from that <Switch> always come in the same element where <Link> elements were used?
I am beyond confused as to where these tags should be used in relation to other tags - not how to get them to work.
Finally, if I have a react app where index.js renders App.js. App.js is like a table of content of the main components I am rendering. Let's say: Header, Main, Footer. Inside the Header there are Greeting and then a NavigationBar. I want my links to be in the NavigationBar component as menu items. Where do I implement react-router components?
Thank you very much in advance.
1 . You can import and use BrowserRouter either in the root of the project which is index.js or in app.js just make sure it wraps around the Switch and Routes .
2 . The Switch Component must wrap all the Route components so this format is the most common way of using it :
<Switch>
<Route exact component={<Component />} path="/" />
</Switch>
You can use NavLink or Link almost anywhere in your components which are imported in Route component prop .
NavLink and Link is just for navigating between Routes in your app .
And for the last part you can have a Layout.js component to have Header Main and Footer components inside of it wrap all the other components which are used in Routes for example :
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
// Router
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
,
document.getElementById('root')
);
App.js
import React from "react";
// Router
import { Switch, Route, withRouter } from "react-router-dom";
// Components
import Home from "./routes/Home/Home";
function App() {
return (
<Switch>
<Route exact component={Home} path="/" />
</Switch>
);
}
export default App;
Home.js
import React from "react";
// Router
import { NavLink } from "react-router-dom";
// Components
import Layout from "../../components/Layout/Layout";
function Home(props) {
return (
<Layout title="Homepage">
<NavLink to="/ss">ss</NavLink>
<NavLink to="/">/</NavLink>
</Layout>
);
}
export default Home;
Define Header Footer and Main in Layout.js :
Layout.js
import React, { Fragment } from "react";
import { Helmet } from "react-helmet";
// Components
import Header from "../Header/Header";
import Footer from "../Footer/Footer";
function Layout({ title, children }) {
return (
<Fragment>
<Helmet>
<title>
{title}
</title>
</Helmet>
<Header />
{children}
<Footer />
</Fragment>
);
}
export default Layout;
The children prop is basically the Home.js component which has Layout wrapper so the Home.js component will display Header Footer from layout and it's own content .
This is the most common way of using the react-router-dom in a react project .
Note
The Switch component will only render the first route that matches/includes the path. Once it finds the first route that matches the path, it will not look for any other matches. Not only that, it allows for nested routes to work properly, which is something that Router will not be able to handle.
Fragment is just for wrapping the component tags like this :
import React , { Fragment } from 'react';
function Component() {
return (
<Fragment>
<Other />
<Main />
</Fragment>
);
}
If you delete Fragment it will throw an error you can read more about Fragments here .

Redirect in React Router 5 is successfully redirecting, but not rendering the child component

I have changed the routes in my app, and in case any users have bookmarked urls to the old routes I have added some redirects to the new routes. Most of them are working fine, however this one is not -
App.tsx
import { Router } from 'react-router-dom';
import Routes from './Routes';
import history from './history';
const App: FunctionComponent = () => (
<Router history={history}>
<Routes />
</Router>
);
export default App;
RouteSwitch.txs
import React, { FunctionComponent } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
const RouteSwitch: FunctionComponent = () => {
return (
<Switch>
<Redirect exact from="/documents" to="/documents/list" />
<Route exact path="/documents/list">
<DocumentsContainer />
</Route>
</Switch>
);
};
export default RouteSwitch;
The redirect from /documents to /documents/list works, however the DocumentsContainer does not get rendered. If I directly request /documents/list then it renders fine. It's as if <Switch> finds its first match (the Redirect) and then decides its job is done. I tried adding the push prop to the Redirect but it didn't make a difference.
My example is very similar to the one given on the React Training site - https://reacttraining.com/react-router/web/api/Redirect/from-string
Thoughts?
Problem solved - the DocumentsContainer component was actually rendering, but just not showing anything due to a quirk with how the use of the redirect was causing a loader count to be incremented by one (but not decremented) resulting in the loader count not returning to 0 to allow document data to be loaded from Redux and the content to be rendered.

React cannot find exported renderRoutes function

I am working on my first meteor/react application and I am trying to use react-router. However, when I try to run the app, I can't seem to import the renderRoutes function.
I am trying to follow along with the router part here:
https://guide.meteor.com/react.html
The router lives in myapp/client/lib/router.js. Here is my router code:
import React from 'react';
import { Router, Route, Switch } from 'react-router';
import createBrowserHistory from 'history/createBrowserHistory';
import {Home} from '../home/home.js';
import {Login} from '../login/login.js';
import {Connect} from '../connect/connect.js';
const browserHistory = createBrowserHistory();
export const renderRoutes = () => (
<Router history={browserHistory}>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/login" component={Login}/>
<Route exact path="/connect" component={Connect}/>
</Switch>
</Router>
);
I have a meteor.startup() function in myapp/server/main.js, this is all I have in there:
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import { renderRoutes } from '../client/lib/router.js';
Meteor.startup(() => {
render(renderRoutes(), document.getElementById('App'));
});
When I try to run meteor run, here's what I see:
Error: Cannot find module '../client/lib/router.js'
Why? Any help is appreciated!
It is because your router is located in
myapp/client/lib/router.js
whereas your main file is located in
myapp/server/main.js
So unless you intend to implement server-side-rendering, you may move the second code to
myapp/client/main.js
This is due to Meteor's project-structure awareness. If a file is contained in a folder, named client or server it will only be available in this environment.
More to read in the guide: https://guide.meteor.com/structure.html#special-directories

Browser showing same component for all routes

I'm using react to recreate a simple route example. Currently only App component is being displayed even if I type anything else after 'localhost:3000/#/' I want to display App component when 'localhost:3000/#/' is called and a Whoops404 component for wildcard. However if I swap the route lines and write Whoops404 component first then every URI shows the Whoops404 component. Whatever route is written first starts showing in browser for every URI. Please let me know what am I missing?
My index.js code is as follows
import React from 'react'
import {render} from 'react-dom'
import {App} from './components/App'
import {Whoops404} from './components/Whoops404'
import {BrowserRouter, Switch, Route} from 'react-router-dom'
window.React = React
render(
<BrowserRouter>
<div>
<Switch>
<Route path = '/' component = {App}/>
<Route path = '*' component = {Whoops404}/>
</Switch>
</div>
</BrowserRouter>,
document.getElementById('react-container'));
You need to add 'exact' keyword in your Route
` <Switch>
<Route exact path = '/' component = {App}/>
<Route exact path = '*' component = {Whoops404}/>
</Switch>`

Rendering React component in Redux application with React-Router v4

This is my first crack at trying to integrate React-Router4 into a React/Redux app. I've been stuck on the first hurdle for a couple hours as I'm reading the docs and a (very good) CSS-Tricks article.
The issue is that the won't render the 'Whatever' value I input at the component prop, which should be a component.
I've actually read almost entirely thru the (excellent) docs, beginning here: https://reacttraining.com/react-router/web/guides/quick-start
And I've consulted this article: https://css-tricks.com/react-router-4/
Which also includes this Codepen (to see if I did something obvious/stupid): https://codepen.io/bradwestfall/project/editor/XWNWge?preview_height=50&open_file=src/app.js
I'm just hoping someone on SO might be able to nudge me over this hump. I was expecting to at least be able to render this very simply without any additional libraries or adjustment to my stores based on: https://reacttraining.com/react-router/web/guides/redux-integration
entry point, index.js:
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import store from './stores'
import { Provider } from 'react-redux'
import Home from './components/Home'
import TopStories from './components/TopStories'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
// app entry point
const app = (
<Provider store={store.configure(null)}>
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/topstories" component={TopStories} />
</Switch>
</Router>
</Provider>
)
// virtual DOM render
ReactDOM.render(app, document.getElementById('root'))
TopStories.js component (renders ok in the '/' path if I switch it w/ Home)
import React, { Component } from 'react'
export default (props) => {
return(
<div>Top Stories component </div>
)
}
I was attempting to test by typing the path into the browswer.... Duh. I just needed to set up a quick link component and everything worked fine.

Resources