Deeplink routing is not working as intended with multiple routes - javascript

I am using react-router-dom#^4 and I am trying to render some deeply routed components. Here is a simplified version of my Base component.
export default function Base() {
return (
<Layout>
<Switch>
<Route exact path="/browse" component={Browser} />
</Switch>
</Layout>
);
}
This, in turn, will render the following component.
export default function Browser() {
return (
<Switch>
<Route exact component={ProjectPicker} />
<Route exact path=":projectId" component={ProjectDetail} />
</Switch>
);
}
While the root (/browse) does work, when I navigate into /browse/1 manually, it will fail. It essentially just renders nothing at all
Why is deeplinking failing here?

I think you need to add / in you path name
`<Route exact path="/:projectId" component={ProjectDetail} />`
see this official guide. https://reacttraining.com/react-router/web/example/url-params

Related

Should I be using functions instead of classes for pages in ReactJS?

I've noticed React Router DOM (v6) is now using functions in their help guides in regards to pages instead of using classes.
Previously used classes like so:
export class Login extends React.Component {
render() {
return <p>test</p>
}
}
However, after trying the latest version of React Router DOM I would receive an empty page for the navigation route.
import {Login} from "./js/components/Auth/Login";
function App() {
return <h2>Test</h2>
}
if (document.getElementById('app')) {
ReactDOM.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/login" component={() => <Login />} />
</Routes>
</BrowserRouter>, document.getElementById('app'))
}
App works fine ('/' route), but /login returns an empty page with no error..
Login refers to a class that uses render() and returns <p>test</p>
Am I doing something incorrectly? Are libraries leaning towards functions instead of class components?
This guide seems to be only using functions for components.
https://reactrouter.com/docs/en/v6/getting-started/tutorial
Class vs Function components is irrelevant in RRDv6, they simply render React components specified as JSX, not as a reference to a component, and not as a function returning JSX. There is also no render or component props, the Route components now use only element to render the route components.
<Routes>
<Route path="/" element={<App />} />
<Route path="/login" element={<Login />} />
</Routes>

What is wrong with the structure of my 'BrowserRouter', 'Routes' and 'Route' in my function App()?

I am attempting to follow a tutorial while learning React.JS and I am running into an issue because the tutorial is using an older version of React and I am stuck trying to figure out how to use BrowserRouter, Routes, and Route.
Can anyone assist me in trying to re-structure the code so it works with the updated version of React? I have tried reading through documentation and tried to mix around a few solutions with no success. Any help is much appreciated!
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import "bootstrap/dist/css/bootstrap.min.css";
import Navbar from "./components/navbar.component.js";
import PortfolioList from "./components/portfolio-list.component";
import EditPortfolio from "./components/edit-portfolio.component";
import CreatePortfolio from "./components/create-portfolio.component";
import CreateUser from "./components/create-user.component";
function App() {
return (
<Routes>
<Navbar />
<br/>
<Route path="/" exact component={PortfolioList} />
<Route path="/edit/:id" exact component={EditPortfolio} />
<Route path="/create" exact component={CreatePortfolio} />
<Route path="/user" exact component={CreateUser} />
</Routes>
);
}
export default App;
The following is the 'error' I'm generating on runtime:
Error: [Navbar] is not a 'Route' component. All component children of
'Routes' must be a 'Route' or 'React.Fragment'
Only Route components and React.Fragments can be a child of the Routes component, and vice-versa. Move the non-Route components out of Routes. The Route component API also changed in version 6, there is no longer render and component props, the routed components are passed to the element prop as JSX, and routes are now always exactly matched, so there's no longer the exact prop as well.
function App() {
return (
<>
<Navbar />
<br/>
<Routes>
<Route path="/" element={<PortfolioList />} />
<Route path="/edit/:id" element={<EditPortfolio />} />
<Route path="/create" element={<CreatePortfolio />} />
<Route path="/user" element={<CreateUser />} />
</Routes>
</>
);
}
you can use the "BrowserRouter" tag followed by the "Switch" tag then you can now use the "Route" tag to specify the path of each component
you can use the "BrowserRouter" tag followed by the "Switch" tag then you can now use the "Route" tag to specify the path of each component.
return (
<>
<BrowserRouter>
<Switch>
<Route path="/" exact component={DashBoard} />
<Route path="/specialistes" exact component={Specialistes} />
<Route path="/findgarages" exact component={FindGarage} />
<Route path="/garages" exact component={Garages} />
</Switch>
</BrowserRouter>
</>
)````

React - TypeError: Cannot read property 'push' of undefined, already exported default withRouter

I have a page component SimulationReport that I want to redirect to upon clicking a button from the Reports page component. This is the App component with the Router:
function App() {
return (
<React.Fragment>
<Router>
<NavigationBar />
<Sidebar />
<Switch>
<Route exact path="/" component={Ratings} />
<Route path="/LeagueSettings" component={LeagueSettings} />
<Route path="/Fixtures" component={Fixtures} />
<Route path="/Reports" component={Reports} />
<Route path="/SimulationReport" component={SimulationReport} />
</Switch>
</Router>
</React.Fragment>
);
}
And here are the relevant code bits from Reports which is a function component:
import {withRouter} from "react-router-dom";
<td>
<Button variant="primary" onClick={handleSimView(index)}>
View
</Button>
</td>
const handleSimView = index => e => {
console.log("index: " + index);
loadSimulationResult(simulationIds[index]);
props.history.push("/SimulationReport");
};
And at the end of the file I have this:
export default withRouter(Reports);
Upon clicking the button, I receive this error:
TypeError: Cannot read property 'push' of undefined
I'm not sure what I need to do to redirect this? Or maybe I should be doing it a different way?
Seems that your prop history is not being passed from the <Route> tag in your component.
You can pass props to a Route Rendered Component by doing the following line:
<Route
path='/SimulationReport'
render={(props) => <SimulationReport {...props} history={yourHistoryObjectForTheRouter} />}
/>
where yourHistoryObjectForTheRouter would be your custom history exported object.
EDIT: Updated code
UPDATE TO ANSWER TO ADDRESS OP's NEEDS:
1° Alright, so first you'll need to install the package called history to your React Application. (You can use npm i history or yarn add history. It depends on what you have installed. If you don't know what's yarn then use the npm option)
2° Somewhere in your project inside the App folder (src/App/), you're going to create another folder called history and inside index.js.
The contents of the index.js file are going to be the next ones.
import { createBrowserHistory } from 'history';
export default createBrowserHistory({});
3° Once that is done, head to your App/index.js file, where you have your <Router> main tag. If you've done everything as I stated before, in that App/index.js you're going to add a new import:
import history from "./history";
Which is your new Custom History Object.
Here you can choose two paths of how you want to solve your problem
=== First Solution
4° Scroll down in that same file, until you find your <Router></Router> tag, and you're going to update it to this next part:
<Router>
<NavigationBar />
<Sidebar />
<Switch>
<Route exact path="/" component={Ratings} />
<Route path="/LeagueSettings" component={LeagueSettings} />
<Route path="/Fixtures" component={Fixtures} />
<Route path="/Reports" component={Reports} />
<Route
path='/SimulationReport'
render={(props) => <SimulationReport {...props} history=
{history} />}
/>
</Switch>
</Router>
After this, you'll have your Custom History Object setted up and your component now should work.
This solution however will only work for that specific component Route, and that means that you will have to do the same for the other <Route > that require the use of the history object.
Stop here if you choose this solution.
=== Second Solution
This solution is better, because you'll now have access to your history object globally, just with an import.
4° Scroll down in that same file, until you find your <Router></Router> tag, and you're going to update it to this next part:
<Router history={history}> //Here's the change
<NavigationBar />
<Sidebar />
<Switch>
<Route exact path="/" component={Ratings} />
<Route path="/LeagueSettings" component={LeagueSettings} />
<Route path="/Fixtures" component={Fixtures} />
<Route path="/Reports" component={Reports} />
<Route path="/SimulationReport" component={SimulationReport} />
</Switch>
</Router>
After this, you'll have your Custom History Object setted up.
5° Navigate to the file that contains the Reports functional component, and on the imports at the top of your file, you're going to import the same history as you did in App/index.js. Beware that depending on the level of subfolders that your Reports components is in, it's how the import is going to change. It can end up like this:
import history from "../history";
or this
import history from "../../history";
it depends or even more "../". It depends on your subfolder levels
After that, you'll need to update your function handleSimView so instead of doing this:
const handleSimView = index => e => {
console.log("index: " + index);
loadSimulationResult(simulationIds[index]);
props.history.push("/SimulationReport");
};
do this:
const handleSimView = index => e => {
console.log("index: " + index);
loadSimulationResult(simulationIds[index]);
history.push("/SimulationReport"); //Change is here, removed "props."
};
After this, your code should work. This solution you can implement it everywhere as you would only need to import the history object and just use it.
I'll be waiting to hear from you to see if it worked. If anything else happens, you can ask me.

React Switch not rendering different pages

I got a react app that got a component that renders my HomePage. I decided to create another component so i can switch between pages on the site. For the HomePage it works when i enter the site, but clicking on navlinks is not working, also if i type the url /contacto i am not getting the render of Contact component, i get the render of the HomePage component, it's not switching between them.
class ContactPage extends Component {
render() {
return <div>HOLA</div>;
}
}
function App() {
return (
<BrowserRouter>
<Switch>
<Route path="/" component={HomePage} />
<Route path="/contacto" component={ContactPage} />
</Switch>
</BrowserRouter>
);
}
Add exact to your HomePage route:
<Route exact path="/" component={HomePage} />
This is because the path / still matches in a non exact way to /contacto and the router renders the first match (that being your HomePage).
By adding exact, you're telling it not to match partial matches.

Render child component over parent

I need to render component with another route but this component must not cover all page. For example, I clicked on some question from stackoverflow list, and than I will receive animate from right to left modal, and I need to change route also
React router (I am using V4)
export default (
<Switch>
<App>
<Route exact={true} path="/" component={App} />
<Route exact={true} path="/product/:id" component={Product}/>
</App>
</Switch>
);
My product container looks like
export default function productContainer(ChildComponent) {
class ProductContainer extends Component {
render = () => {
return <ChildComponent/>
}
}
return ProductContainer;
}
And my product component
class Product extends Component {
render = () => {
return ("")
}
}
export default productContainer(Product);
When I emulate situation, which I describe above, my page fully rerendred and I don't see my App component Page
Have any idea, how I can resolve this issue?
People have asked how to render a modal as a route before in react-router without re-rendering (can't find the discussion right now). Essentially with react-router this is not possible. Each route change causes a re-render. That said, you can do what you want by nesting your routes.
Each component can return routes, so by using composition you can choose where to render any route.
For instance,
export default (
<Switch>
<App>
<Route path="/" component={App} />
</App>
</Switch>
);
Inside <App /> -
render() {
return (
<Something>
<PageHeader />
<Switch>
<Route path="/product/:id" component={Product}/>
</Switch>
</Something>
);
}
So you can see, if you were to add your routes inside the App component, they can all share a common page layout.
Remember: Any component can return multiple routes or just a single one inside a Switch! Switch will only render the first route that matches.
Also Remember: Routes inside a switch must be a direct child, you can't have Switch -> App -> Route, it must always be a direct child like Switch -> Route
Use render property instead of component in Route.
<Route exact={true} path="/" render={() => (
<div>
<App />
<Route exact={true} path="/product/:id" component={Product}/>
</div>
)} />

Categories

Resources