How to define child routes as react components in react-router? - javascript

I have main.js:
import { render } from 'react-dom';
import { browserHistory, Router, Route, IndexRoute } from 'react-router';
import Home from './containers/Home';
import ApplicationsRoutes from './applications/routes';
render((
<Router history={browserHistory}>
<Route path="/" component="div">
<IndexRoute component={Home} />
<ApplicationsRoutes />
</Route>
</Router>
), document.getElementById('app'));
And /application/routes.js :
import { browserHistory, Router, Route, IndexRoute } from 'react-router'
import ApplicationsHome from './containers/ApplicationsHome';
export default () => (
<Route path="applications" component={ApplicationsHome} />
);
I was expecting that route from /application/routes.js will be added to the main router and so ApplicationsHome will be rendered for path /applications
Unfortunately, this is not a case. I am getting error:
Location "/applications" did not match any routes
For me it looks like such a way to compose Router does not work, but I cannot understand what is right way to do this.

In general, when you do this, you should consider using the PlainRoute syntax instead of the JSX syntax, then use getChildRoutes on the parent routes to resolve the child routes, per the huge-apps example: https://github.com/rackt/react-router/tree/master/examples/huge-apps
This will then let you easily configure code-splitting and dynamic routes down the road.

For singular routes you can export your route as a JSX element:
export default <Route path="applications" component={ApplicationsHome} />;
And include it like this:
{SomeRoute}
For multiple routes you can't export them as you have in a function, you'll get a JSX error saying you can't have adjacent components without a wrapping element. In that case you would have to do:
export default (
<Route>
<Route path="/about" component={About} />
<Route path="/services" component={Services} />
</Route>
);
And use it:
{ApplicationsRoutes}

Related

react-router-dom 6.8.1 and react 18.2.0 <Link> only updated URL

I'm using react-router-dom 6.8.1 and react 18.2.0 and trying to set up browser router using the createBrowserRouter() and createRoutesFromElements() functions. I'm then rendering my browser router using the <RouterProvider> component, and the front page of my website displays fine (the App component does). For some reason, any react-router-dom <Link> components I place in my components appear on the front page, but when I click them, only the URL changes, and it does not update the UI. What's weird is that if I use an <Outlet>, the UI from the child routes will display when I click any links, but that's not what I want. I need to navigate to a separate page.
Here's where I'm creating the browser router:
import * as ReactDOM from 'react-dom/client';
import {
createBrowserRouter,
createRoutesFromElements,
Route,
RouterProvider,
} from 'react-router-dom';
import App from './app/app';
import ParticipantProfile from './app/profiles/participantProfile';
const browserRouter = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<App />}>
<Route path="profile" element={<ParticipantProfile />} />
</Route>
)
);
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(<RouterProvider router={browserRouter} />);
Here's where I create my <Link>:
import { Link } from 'react-router-dom';
import { createTheme } from '#mui/material/styles';
const theme = createTheme();
function App() {
return <Link to="profile">Profile</Link>;
}
export default App;
I'm tried rendering the <BrowserRouter> component itself instead of using createRoutesFromElements, but same results. Changing the path from profile to /profile also seems to do nothing.
If you want each route to map to a different component (without layout nesting), there is no need to wrap them all under a single <Route> element.
<>
<Route path="/" element={<App />} />
<Route path="/profile" element={<ParticipantProfile />} />
</>
Alternatively, only specify the element on the child route.
<Route path="/">
<Route index element={<App />} />
<Route path="profile" element={<ParticipantProfile />} />
</Route>

Can't get react-router-dom to work (seeing blank page)

This is my App component that has 3 child components: Home, Contact and Procedures. I'm trying to make each child component into its own url route.
However right now I'm just seeing a blank page
FYI- I'm using react-router-dom#6.0.2
import {BrowserRouter, Routes, Route} from 'react-router-dom';
import Home from './Home.js'
import Contact from './Contact.js'
import Procedures from './Procedures.js'
import './App.css';
function App() {
return (
<BrowserRouter>
<Routes>
<Route exact path="/" component={Home} />
<Route path="/procedures" component={Procedures} />
<Route path="/contact" component={Contact} />
</Routes>
</BrowserRouter>
);
}
export default App;
In react-router-dom version 6 you should use element instead of component, also be sure to reference the element you want to render as JSX. By the way, there is no longer any "exact" attribute.
Should look like this on your code:
<Route path="/" element={<Home />} />

Migrate 'react-router' into 'react-router-dom' (v4)

I am learning React Routing and I am watching this tutorial:
https://www.youtube.com/watch?v=1iAG6h9ff5s
Its 2016 tutorial so I suppose something changed because 'react-router' not working anymore and I am supposed to use 'react-router-dom'.
I found that I must uninstall 'history' and 'react-router' and use 'react-router-dom' instead, but It not working as expected when I change it.
How to edit this to make it working with 'react-router-dom'?
import React from "react";
import ReactDOM from "react-dom";
import {Router, Route, IndexRoute, hashHistory} from "react-router";
import Layout from "./pages/Layout";
import Archives from "./pages/Archives";
import Featured from "./pages/Featured";
import Settings from "./pages/Settings";
const app = document.getElementById('app');
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={Layout}>
<IndexRoute component={Featured}></IndexRoute>
<Route path="archives" component={Archives}></Route>
<Route path="settings" component={Settings}></Route>
</Route>
</Router>,
app);
My edit:
import React from "react";
import ReactDOM from "react-dom";
import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
import Layout from "./pages/Layout";
import Archives from "./pages/Archives";
import Featured from "./pages/Featured";
import Settings from "./pages/Settings";
const app = document.getElementById('app');
ReactDOM.render(
<Router>
<Route path="/" component={Layout}>
<Route path="/featured" component={Featured}/>
<Route path="/archives" component={Archives}/>
<Route path="/settings" component={Settings}/>
</Route>
</Router>,
app);
Also pushState not working...
Layout.js
import React from "react";
import {Link} from "react-router-dom";
export default class Layout extends React.Component {
navigate() {
this.props.history.pushState(null, "/");
}
render() {
return (
<div>
{this.props.children}
<h1>Welcome</h1>
<button onClick={this.navigate.bind(this)}>Featured</button>
</div>
);
}
}
When I click to Link url change, but content is not loaded... Also when I access url I get "Cannot GET" error
After watching the video, you probably want something like this. At first this would not be so easy to understand but after seeing a few of them you digest it. First you render your Layout with one Route. Then in this top route, you use other Routes to setup your components.
We usually use exact props for a top root like /. If you don't setup your app like that, for example all your routes is in your top Router config, then to use a route something like /featured we must have exact prop. If we don't use it Router always hit / path and we always see the top level component.
But, in your situation, you want other components to be routed in your top level component. So, we drop exact prop here.
Also you can use push to change history.
Update
After think about the navigation button named "Featured", I think you want the Featured component rendered as default one here. When hit the button again you will come back to Featured one. I've changed the code according to that. In this version, we add a / route in the Layout and point it to Featured. So, when we come here it is rendered. But, we use exact prop here since we also want routes like "/featured", "/archives" and "/settings".
export default class Layout extends React.Component {
navigate = () => this.props.history.push("/");
render() {
return (
<div>
<h1>Welcome</h1>
<Link to="/featured">Featured</Link>
<Link to="/archives">Archives</Link>
<Link to="/settings">Settings</Link>
<br />
<button onClick={this.navigate}>Featured</button>
<Route exact path="/" component={Featured} />
<Route path="/featured" component={Featured} />
<Route path="/archives" component={Archives} />
<Route path="/settings" component={Settings} />
<div>
Some other info.
</div>
</div>
);
}
}
const app = document.getElementById('root');
ReactDOM.render(
<Router>
<Switch>
<Route path="/" component={Layout} />
</Switch>
</Router>,
app);

How do I handle Multiple Routes In App.js?

I'm new to react and now learning react-router.
I am trying to have multiple routes within the BrowserRouter and I am not sure why it isn't working.
My code is this
import React, { Component } from 'react';
import {database} from '../firebase';
import _ from 'lodash';
import ReactDOM from 'react-dom';
import {BrowserRouter, Route, Switch, Link} from 'react-router-dom';
import List from './List';
import NewPost from './NewPost';
class App extends Component {
render() {
return (
<div className="App container">
<header className="App-header">
<h1 className="App-title">Here We Go Again</h1>
</header>
<hr/>
<BrowserRouter>
<Switch>
<Route path='/' component={List}/>
<Route path='/new' component={NewPost}/>
</Switch>
</BrowserRouter>
</div>
);
}
}
export default App;
Regardless of the path I go to, it only shows the first one in the list. I have tried moving them around so I know that for sure. And the functionality of them all still work. It's just a matter of rendering them one at a time.
<BrowserRouter>
<Switch>
<Route path='/' component={List}/>
<Route path='/new' component={NewPost}/>
</Switch>
</BrowserRouter>
As you can see I tried some other possible solutions on stack overflow liek adding Switch but it still didn't work.
Any idea how to fix it or what I'm doing wrong?
You need to add the word exact to the first route. It is currently matching anything with a /.
<BrowserRouter>
<Switch>
<Route path='/' exact component={List}/>
<Route path='/new' component={NewPost}/>
</Switch>
</BrowserRouter>

Can't make React-Router render two different components, always render root

I have these two components that are completely independent of each other. I want to render App when I enter / and render About when I go to /#/about
I got this piece of code (but I tested quite a few others):
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Link, browserHistory } from 'react-router'
import App from './App';
import About from './About';
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={App} >
<Route path="/about" component={About} />
</Route>
</Router>
, document.getElementById('root')
);
I also tried something like
<Route path="/about" component={About} />
<Route path="/" component={App} />
And changed /about to /#/about, about
But it always render the "fallback" /, it always goes to this route, no matter what.
How can I make this app navigate properly to / and /about and render the App and the About components?
#edit
Assuming that my About component is broken, I removed the first Route and kept only the /about (kept only the /about Route) :
<Route path="/about" component={App} />
(I tried keeping About as well in a previous test) and also changed the /about to about and /#/about.
And I get this error on console:
"VM3651 bundle.js:30801 Warning: [react-router] Location "/#/about" did not match any routes"
#edit 2
I made a change, following the example #Dominic posted. I had to make some modifications to make sure both components would render. I added the {this.props.children} to all Components to understand what would happen.
//imports
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={About} >
<IndexRoute component={App} />
<Route path="/about" component={Other} />
</Route>
</Router>
,document.getElementById('root'));
The route http://localhost:3000/#/about is rendering:
> About > App
So it is rendering the IndexRoute, it is not getting caught by the /about.
And this is now exactly what I need, because I didn't want a root component, I wanted 2 routes to 2 different and isolated components. I need something like two sibling routes.
#edit
The About.js
import React, { Component } from 'react';
class About extends Component {
render() {
return (
<div>
About page
{this.props.children}
</div>
);
}
}
export default About;
Solution:
Since I'm using a HASH (#) in the URL, I should use hashHistory from React Router in the <Router history={hashHistory}>
You're confusing how routes work - About is a child of the App route, so in order to render About, it has to render App.
In other words your App component is the "shell" and all components under it render INSIDE it (via props.children).
You should add another route to render /.
import { ..., IndexRoute } from 'react-router'
<Route path="/" component={App} >
<IndexRoute component={Home} />
<Route path="about" component={About} />
</Route>
Your App does not contain route specific content, it would be something more like this:
<div id="app">
<nav>app navigation</nav>
<main class="route-content">{props.children}</main>
</div>
Docs: https://github.com/ReactTraining/react-router/blob/master/docs/guides/RouteConfiguration.md#adding-an-index
Those routes look correct to me. Are you getting any errors in the console? Maybe your About component is undefined and thus not rendering. Can you post your About component?

Categories

Resources