Using react-router with reconcilers such as react-three-fiber - react-router

I'm try to use react-router with react-three-fiber. The issue is the <Switch> components lose their context when added inside a react-three-fiber <Canvas> element. To fix this I can wrap the switch inside a <Router> inside the Canvas. And the routes work as expected when manually typing the url. However, the ` elements now seem to reference another Router and don't work when clicked.
Is there a way to make the elements inside and outside the <Canvas> reference the same router?
https://codesandbox.io/s/reach-router-starter-v1-9qcjc
const App = ({ router }) => {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Canvas>
<Plane color="black" position={[-5, 0, 0]} />
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</Router>
</Canvas>
</div>
</Router>
);
};
const Home = () => <Plane color="red" position={[0, 0, 0]} />;
const About = () => <Plane color="green" position={[0, 0, 0]} />;
const Dashboard = () => <Plane color="blue" position={[0, 0, 0]} />;

You can use npm i wouter instead of react-router-dom https://www.npmjs.com/package/wouter
Wrap everything as you normally would using react-router-dom but use wouter instead. Note that top level Router component is fully optional.
App.js :
import Nav from './Nav'
import { Router, Switch, Route } from 'wouter';
make App.js a class component and structure like so:
<Nav />
<Router/>
<Switch />
<Route exact path="/somelink" component={Somecomponent}/>
<Switch />
<Router/>
export default App;
Nav.js component:
import { Link } from 'wouter'
const Nav = () => {
return (
<nav className="navigation">
<ul>
<li>
<Link to="/somecomponent">...</Link>
</li>
</ul>
</nav>
)
}
export default Nav;

Related

I am using react router v5. Clicking the links, changes url, but component is still the same [duplicate]

I am building a Netflix clone application, and I am using react-router-dom v5 to switch between different pages. However, when I click the Link tag in Navbar.jsx, the URL changes, but the corresponding component doesn't render. I have consulted numerous StackOverflow posts on this topic, however, I can't get it to work. Below is the code. Please help me, as I'm stuck on this for 3 days 😥.
What it should show, when navigating to /series from /:
What it is actually showing:
index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const container = document.getElementById("root");
const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
App.jsx
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import "./app.scss";
import Home from "./pages/home/Home";
import Watch from "./pages/watch/Watch";
const App = () => {
return (
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/movies">
<Home type="movies" />
</Route>
<Route path="/series">
<Home type="series" />
</Route>
<Route path="/watch">
<Watch />
</Route>
</Switch>
</Router>
);
};
export default App;
Home.jsx
import React from "react";
import Featured from "../../components/featured/Featured";
import Navbar from "../../components/navbar/Navbar";
import "./home.scss";
const Home = ({ type }) => {
return (
<div className="home">
<Navbar />
<Featured type={type} />
</div>
);
};
export default Home;
Navbar.jsx
import React, { useState } from "react";
import "./navbar.scss";
import { Link } from "react-router-dom";
const Navbar = () => {
const [isScrolled, setIsScrolled] = useState(false);
window.onscroll = () => {
setIsScrolled(window.scrollY === 0 ? false : true);
return () => window.onscroll == null;
};
return (
<div className={`navbar ${isScrolled ? "scrolled" : ""}`}>
<div className="container">
<img src="./netflix_logo.jpg"
alt="netflix logo"
/>
<Link to="/" className="link">
<span>Home</span>
</Link>
<Link to="/series" className="link">
<span>Series</span>
</Link>
<Link to="/movies" className="link">
<span>Movies</span>
</Link>
<Link to="" className="link">
<span>New and Popular</span>
</Link>
<Link to="" className="link">
<span>My List</span>
</Link>
</div>
</div>
);
};
export default Navbar;
Featured.jsx
import "./featured.scss";
import { IoMdPlay } from "react-icons/io";
import { FiInfo } from "react-icons/fi";
const Featured = ({ type }) => {
return (
<div className="featured">
{type && (
<div className="category">
<span style={{ color: "white" }}>
{type === "movies" ? "Movies" : "TV Series"}
</span>
<select name="genre" id="genre">
<option>Genre</option>
<option value="adventure">Adventure</option>
<option value="comedy">Comedy</option>
<option value="crime">Crime</option>
<option value="fantasy">Fantasy</option>
<option value="historical">Historical</option>
<option value="horror">Horror</option>
<option value="romance">Romance</option>
<option value="sci-fi">Sci-fi</option>
<option value="thriller">Thriller</option>
<option value="western">Western</option>
<option value="animation">Animation</option>
<option value="drama">Drama</option>
<option value="documentary">Documentary</option>
</select>
</div>
)}
<img
src="https://m.media-amazon.com/images/M/MV5BNzM4OTkzMjcxOF5BMl5BanBnXkFtZTgwMTkxMjI1MTI#._V1_.jpg"
alt="featured"
/>
<div className="info">
<img
src="https://occ-0-1432-1433.1.nflxso.net/dnm/api/v6/LmEnxtiAuzezXBjYXPuDgfZ4zZQ/AAAABUZdeG1DrMstq-YKHZ-dA-cx2uQN_YbCYx7RABDk0y7F8ZK6nzgCz4bp5qJVgMizPbVpIvXrd4xMBQAuNe0xmuW2WjoeGMDn1cFO.webp?r=df1"
alt=""
/>
<span className="desc">
When a beautiful stranger leads computer hacker Neo to a forbidding
underworld, he discovers the shocking truth - the life he knows is the
elaborate deception of an evil cyber-intelligence.
</span>
<div className="buttons">
<button className="play">
<IoMdPlay className="button-logo" />
<span>Play</span>
</button>
<button className="more">
<FiInfo className="button-logo" />
<span>More Info</span>
</button>
</div>
</div>
</div>
);
};
export default Featured;
There's a compatibility issue between pre-5.3.3 versions of react-router-dom#5 and react#18.
Github Issue #7870
PR #8831 merged to address issue - Fix was merged on May 18th, 2022, react-router-dom v5.3.3.
Solutions
Bugfix was merged into v5.3.3. Update to react-router-dom#5.3.3 or higher.
From the project's root directory run:
npm uninstall -S react-router-dom
npm install -S react-router-dom#5.3.3 (or #latest)
Revert back to React 17 (or React 17 syntax) and fix up the index.js file.
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(
<StrictMode>
<App />
</StrictMode>,
document.getElementById("root")
);
Make the React.StrictMode component a child/descendent of the router component. Comment.
Replace:
<React.StrictMode>
...
<BrowserRouter>
...
</BrowserRouter>
</React.StrictMode>
with:
<BrowserRouter>
<React.StrictMode>
...
</React.StrictMode>
</BrowserRouter>
Upgrade to react-router-dom#6 and fix up the routes.
const App = () => {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/movies" element={<Home type="movies" />} />
<Route path="/series" element={<Home type="series" />} />
<Route path="/watch" element={<Watch />} />
</Routes>
</Router>
);
}
First Solution and Best Solution:
If you use are using React Router 5.3.x, check whether it is 5.3.3 in your package.json file.
If it is not 5.3.3 uninstall the last version then install the bug-free version which has been resolved by John and updated in version 5.3.3.
npm uninstall -S react-router-dom
npm install -S react-router-dom#5.3.3
Second Solution:
React has launched its StrictMode in its latest update.
you can see it in an index.js file
index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
So here your React Router is in the child component. And we have to make it a parent component.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>
);
Third Solution:
Remove the Strict mode from the index.js file
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);

Why does my href tag become blank after I login - ReactJs

I am facing a very weird issue. In my react app, the navbar is something like:
<ul>
<li>
<a href={"/Marketplace"}>Marketplace</a>
</li>
</ul>
I have a simple login feature in my app which redirects the user to the homepage after logging in. After I log in, the href value in the above anchor tag disappears. I can't seem to understand why this is happening. basically, the same code block now becomes:
<ul>
<li>
<a href>Marketplace</a>
</li>
</ul>
If you want to allow users to link to other pages on click, Use Link tag !
for more help react-router-dom
import React from "react";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
const Marketplace = () => {
return <div>This is the Market place</div>;
};
const Home = () => {
return <div>This is the home page</div>;
};
export default function App() {
return (
<div className="App">
<BrowserRouter>
<nav>
<div>
<Link to="/">Home</Link>
</div>
<div>
<Link to="/Marketplace">Marketplace</Link>
</div>
</nav>
<Switch>
<Route path="/Marketplace">
<Marketplace />
</Route>
<Route path="/" exact>
<Home />
</Route>
</Switch>
</BrowserRouter>
</div>
);
}
use Link instead of Anchor Tag if you are using react router
import { Link } from "react-router-dom";
<Link to="/Marketplace">Marketplace</Link>

react-router show different when component is wraped

I'm new react user, when i see react-router docs, I confused.
let me show,
first, the docs url: https://reacttraining.com/react-router/web/example/route-config
I simplify like this
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
const routes = [
{
path: "/",
component: Sandwiches
},
{
path: "/tacos",
component: Tacos
}
];
export default function RouteConfigExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">/</Link>
</li>
<li>
<Link to="/tacos">tacos</Link>
</li>
</ul>
<Switch>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
</Switch>
</div>
</Router>
);
}
function RouteWithSubRoutes(route) {
return (
<Route
exact
path={route.path}
component={route.component}
/>
);
}
function Sandwiches() {
return <h2>/</h2>;
}
function Tacos() {
return (
<div>
<h2>Tacos</h2>
</div>
);
}
now, when i click / show /, but click Tacos show nothing.
what expect, click / show /, and click Tacos show Tacos.
I resolve by these
// first, do not use component wrap
export default function RouteConfigExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">/</Link>
</li>
<li>
<Link to="/tacos">tacos</Link>
</li>
</ul>
<Switch>
{routes.map((route, i) => (
<Route
key={i}
exact
path={route.path}
component={route.component}/>
))}
</Switch>
</div>
</Router>
);
}
// second, do not use Switch
export default function RouteConfigExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">/</Link>
</li>
<li>
<Link to="/tacos">tacos</Link>
</li>
</ul>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
</div>
</Router>
);
}
It bothered me for a long time, now I'm dying to know why, Please tell me in detail, and thanks so much...
In addition, My English is not pretty, understanding...
Switch components only valid children are Route and Redirect, so even though another react component renders a Route it won't work quite in the same way.
Switch children
All children of a <Switch> should be <Route> or <Redirect> elements.
Only the first child to match the current location will be rendered.
Edit
While wrapped Route components can still render, as "grand-children" descendants, it appears that route props are only applied at the root Switch level.
In the following Switch, even though RouteWithSubRoutes specifies the exact prop, RouteWithSubRoutes in the react DOM does not, so only the first element is returned (coincidentally the home "/" route).
<Switch>
{routes.map(route => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>
This following Switch is identical to the above except for specifying exact prop, and this works as expected.
<Switch>
{routes.map(route => (
<RouteWithSubRoutes key={route.path} exact {...route} />
))}
</Switch>
/Edit
It sounds like you have a two-part question, why both resolutions work.
The first attempt at fixing by rendering a Route directly succeeds by specifying the exact prop on all routes within the Switch, which only matches and renders the first matching Route or Redirect. When the path is exactly "/" then that component renders, and when it is exactly "/tacos" then that component renders.
The second attempt you render all the routes just right in the Router, which matches and renders all matching routes, but since you specify, again, the exact prop, it matches a single route and works.
Demo

Trouble migrating to react-router v4

I am having trouble migrating to react router 4 with nested routes. Here was some snippets from my previous code. was my layout container and everything was rendered within that if logged in (otherwise redirect to login)
ReactDOM.render(
<Provider store={ store }>
<div>
<Router history={ history }>
<Route path='/login' component={ Login } />
<Route path="/password/reset" component={PasswordReset} />
<Route path='/register' component={ Register } title={ 'Register' } />
<Route path='/password/change/:token' component={ ChangePassword } title={ 'Register' } />
<Route component={ EnsureLoggedInContainer }>
<Redirect from='/' to='/dashboard' />
<Route path='/' component={ App }>
<Route path='/logout' component={ Logout } />
....
</Router>
</div>
within to render the children components:
class ContentLayout extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
let children = null;
if (this.props.children) {
children = React.cloneElement(this.props.children, {
updateHeader: this.props.updateHeader,
});
}
return (
<div className={ this.props.cls }>
<MainHeader
updateHeader={ this.props.updateHeader }
header={ this.props.header }
/>
{children}
</div>
);
}
}
With v4 I've been trying to figure out the proper way to render as the layout and any child components within. So far I've been trying to get it working but feel I am on wrong path. (Currently props.match always points to '/')
ReactDOM.render(
<Provider store={ store }>
<ConnectedRouter history={history}>
<div>
<Switch>
<Route exact path='/login' component={ Login } />
<Route exact path="/password/reset" component={PasswordReset} />
<Route exact path='/register' component={ Register } />
<Route exact path='/password/change/:token' component={ ChangePassword } />
<Route path='/' component={ App } />
</Switch>
</div>
</ConnectedRouter>
</Provider>,
document.getElementById('app')
);
Within App
const RouteWithProps = ({ component: Component, props, ...extraProps})=> {
return (<Route
{...extraProps}
render={() => <Component {...props} {...extraProps} />}
/>
);
}
and with the component rendering
{securedRoutes.map((route, i) => (
<RouteWithProps key={i} {...route} updateHeader={this.props.updateHeader} location={this.props.location} match={this.props.match} />
))}
What is the proper way or a good example of how to structure the app so for all logged in routes the layout is
<App>
<ContentLayout>
<Child>
with App passing props like updateHeader and anything else to all children.
I got it working by removing passing location and match to RouteWithProps.
I had an issue with the RouteWithSubRoutes example in dealing with nested routes for things like /.../:id and /.../:submit ended up doing this to make work so I can continue working. Do not think this is ideal but will work till another answer on best practices.
const RouteWithProps = ({ component: Component, ...extraProps }) => {
return (<Route exact path={extraProps.path}
{...extraProps}
render={matchProps => <Component {...matchProps} {...extraProps}
/>}
/>
);
}
Also removed passing this.props.location and match to this component.

NavLink not redirecting, if accessed directly

I'm using react-router on a page with navbar and content.
const App = () => (
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/shape/:activeTab" component={Shapes} />
<Redirect from="/shape" to="/shape/triangle" />
</Switch>
</Router>
);
-- Shapes
class Shapes extends React.Component {
getActiveTab() {
switch (this.props.match.params.activeTab) {
case 'triangle':
return Triangle;
case 'circle':
return Circle;
case 'square':
return Square;
default:
return Triangle;
}
}
render() {
return (
<div className="wrapper">
// this is where the navbar renders.
<ul>
<li>
<NavLink exact to={`/shape/triangle`}> Triangle </NavLink>
</li>,
<li>
<NavLink exact to={`/shape/circle`}> Circle </NavLink>
</li>,
<li>
<NavLink exact to={`/shape/square`}> Square </NavLink>
</li>,
</ul>
// this is where the content renders.
<div className="content">
{
this.getActiveTab().data.map(tuple =>
<div>
{tuple.description}
</div>,
)
}
</div>
</div>
);
}
};
Now, when I click localhost:8080/shape I get redirected to proper page with navigation.
Also the navigation works properly (i:e. clicking on Triangle redirects me to localhost:8080/shape/triangle)
But, when I try to access the page localhost:8080/shape/triangle directly, I get a 404!
It works only when I access the /shapes page first and then use the navigation.
What do I need to address here to make sure I can route to shape/* pages.
Note: I'm referring https://reacttraining.com/react-router/web/api/Switch