Unexpected re-rendering of components - react-router

I'm trying to navigate back to a Menu component, but when I trigger a route to do so, the previous rendered Practice component is rendered in the root domain level, which should just be for the Menu component.
The solutions for similar questions on StackOverflow say to use exact in the route, but as you can see I have this in place.
How do I make this work as expected? Thanks.
Here's what I have...
App.js
import React from 'react';
import './App.css';
import PracticeContextProvider from './contexts/PracticeContext';
import {BrowserRouter as Router, Route, Switch, Link} from 'react-router-dom';
import Menu from './pages/Menu';
function App() {
return (
<div className="app">
<PracticeContextProvider>
<Menu />
</PracticeContextProvider>
</div>
);
}
export default App;
Menu.js
import React, { useContext } from 'react';
import {BrowserRouter as Router, Route, Switch, Link, useParams, useLocation, useRouteMatch} from 'react-router-dom';
import { PracticeContext } from '../contexts/PracticeContext';
import Practice from './Practice';
import ModuleLanguageSelector from '../components/ModuleLanguageSelector';
import ModuleListMenuItem from '../components/ModuleListMenuItem';
const Menu = () => {
const { modulesJson } = useContext(PracticeContext);
return (
<div>
<h1>Menu</h1>
<Router>
<Switch>
<Route exact path="/">
<ModuleLanguageSelector />
{ modulesJson && (
modulesJson.map(module => {
return (
<Link to={'/Practice/' + module._id} key={ module._id }>
<ModuleListMenuItem module={ module }></ModuleListMenuItem>
</Link>
)
})
)}
</Route>
<Route exact path="/Practice/:moduleId" component={Practice} />
</Switch>
</Router>
</div>
);
}
export default Menu;
Practice.js
import React, { useContext } from 'react';
import {BrowserRouter as Router, Route, Switch, Link, useParams, useLocation, useRouteMatch} from 'react-router-dom';
import { PracticeContext } from '../contexts/PracticeContext';
import Menu from './Menu';
import ModulePracticeAnswerArea from '../components/ModulePracticeAnswerArea';
import ModulePracticeQuestion from '../components/ModulePracticeQuestion';
import ModulePracticeProgress from '../components/ModulePracticeProgress';
import ModulePracticeTutorial from '../components/ModulePracticeTutorial';
const Practice = () => {
const { moduleId } = useParams();
const { questionIndex } = useContext(PracticeContext);
return (
<Router>
<div className="module-practice-screen">
<h1>Practice</h1>
<div className="module-practice-container">
<Link to={'/'}>
<button className="quit-practice">X</button>
</Link>
{
moduleId ?
<React.Fragment>
{/*<ModulePracticeTutorial moduleId={ moduleId } />*/}
<ModulePracticeProgress questionNumber={ questionIndex } />
<ModulePracticeQuestion moduleId={ moduleId } questionNumber={ questionIndex } />
<ModulePracticeAnswerArea moduleId={ moduleId } questionNumber={ questionIndex } />
</React.Fragment>
:
<h3>The menu should appear here!</h3>
}
</div>
</div>
<Switch>
<Route exact path="/" component={Menu} />
</Switch>
</Router>
);
};
export default Practice;

You don't need <Router> and <Switch> in Practice
const Practice = props => {
const { moduleId } = useParams();
const { questionIndex } = useContext(PracticeContext);
return (
<div>
<div className="module-practice-screen">
<h1>Practice</h1>
<div className="module-practice-container">
<Link to="/">
<button>X</button>
</Link>
{moduleId ? (
<React.Fragment>
{/*<ModulePracticeTutorial moduleId={ moduleId } />*/}
<ModulePracticeProgress questionNumber={questionIndex} />
<ModulePracticeQuestion
moduleId={moduleId}
questionNumber={questionIndex}
/>
<ModulePracticeAnswerArea
moduleId={moduleId}
questionNumber={questionIndex}
/>
</React.Fragment>
) : (
<h3>The menu should appear here!</h3>
)}
</div>
</div>
</div>
);
};
codesandbox

Related

Wrapping h5 in Link tag made h5 dissappear

I am trying to make a component go to localhost:3000/second. The header for the component(AddNote) displays when I dont wrap it in a Link tag, but when I do, the whole page becomes blank, including the "My Notes" which is supposed to be displayed by default.
import React, {useState} from 'react';
import './App.css';
import {BrowserRouter as Router, Routes, Route, Switch} from 'react-router-dom';
import AddNote from './components/noteDisplay/addNote/newNote.js'
import FirstPage from './components/noteDisplay/firstPage.js'
import NoteDisplay from './components/noteDisplay/noteDisplay.js'
import secondPage from './components/secondPage/secondContainer.js'
const App = () => {
return (
<div className="App">
<h1 className="app-title">My notes</h1>
<Router>
<div>
<Routes>
<Route path='/second' element={<secondPage />}/>
{/*<Route path='/' element={<NoteDisplay/>}/>*/}
</Routes>
</div>
</Router>
<AddNote/>
</div>
);
}
import React from 'react';
import { Route, BrowserRouter as Router, Link, Switch } from 'react-router-dom';
import NoteDisplay from '../noteDisplay';
import { v4 as uuidv4 } from 'uuid';
const AddNote = () => {
console.log('hi')
return (
<div>
<Link to="/second">
<h5 className="add-note">New note</h5>
</Link>
</div>
)
}
export default AddNote;
You need to change your <Link /> code to be something like below.
const AddNote = () => {
return (
<div>
<h5>
<Link href="/second">New Note</Link>
</h5>
</div>
);
};
See the official Next.js documentation for how to use it - it explains it in greater detail!

The parameter's value don't display with TS

Goal:
Display the parameter's value in the webpage when you click on the text "DetailView"
Problem:
The value don't display and I am not sure if this tis the correct error for this case.
"The 'jsxFragmentFactory' compiler option must be provided to use JSX fragments with the 'jsxFactory' compiler option.(17016)"
How should I solve it?
Thank you!
Stackblitz:
https://stackblitz.com/edit/react-router-typescript-example-asrnpk?
Other info:
*Newbie in react TS
----------------------------
import * as React from 'react';
import { BrowserRouter as Router, Link, Route, Routes } from 'react-router-dom';
import { render } from 'react-dom';
import { Home, Foo, Bar } from './Pages';
import DetailView from './DetailView';
import './style.css';
class App extends React.Component {
render() {
return (
<Router>
<div>
<nav>
<Link to="/">Home</Link>
<br />
<Link to="/foo">Foo</Link>
<br />
<Link to="/bar">Bar</Link>
<br />
<Link to="/detailview/3}">DetailView</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/foo" element={<Foo />} />
<Route path="/bar" element={<Bar />} />
<Route path="/detailview/:p1?" element={<DetailView />} />
</Routes>
</div>
</Router>
);
}
}
render(<App />, document.getElementById('root'));
----------------
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
interface MatchParams {
id: string;
}
interface Props extends RouteComponentProps<MatchParams> {
// ...
}
const DetailView: React.FC<Props> = ({ match }: Props): JSX.Element => {
const params = match.params;
return <>{`Test "${params.id}"`}</>;
};
export default DetailView;
-------------------
import React from 'react';
export const Home = () => <h1>Home Page</h1>;
export const Foo = () => <h1>Foo Page</h1>;
export const Bar = () => <h1>Bar Page</h1>;

I can't find out what I' doing wrong when I'm using react routes and my content is not displaying properly

My content is displaying normally until I add route and switch. After that my content doesn't display and I cant understand why. I downloaded react-route-dom too.
code from App.js
import './App.css';
import Navbar from './components/Navbar.js'
import HomeView from './components/HomeView.js'
import AboutView from './components/AboutView.js'
import {Switch, Route} from 'react-router-dom'
function App() {
return (
<div>
<Switch>
<Navbar/>
<Route path="/" exact>
<HomeView/>
</Route>
<Route path="/about" component={AboutView}/>
</Switch>
</div>
);
}
export default App;
code from the components
const HomeView = () => {
return(
<div>
<h1>Home</h1>
</div>
)
}
export default HomeView;
const AboutView = () => {
return (
<div>
<h1>About</h1>
</div>
)
}
export default AboutView;
code from index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter} from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);

exitBeforeEnter is not working as intended - Trouble w/ Page Transitions

I'm trying to create a smooth page transition using a combination of react-router-dom and framer-motion, and I'm trying to have my pages fade out on exit and fade in on enter. But exitBeforeEnter is not working how it's supposed to. The page will not fade out on exit but the next page will fade in every time. Below is my code, and I'll attach one of the page files (all of the pages have pretty much the same code).
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(<Router><App /></Router>, document.getElementById('root'));
App.js
import React from 'react';
import About from "./pages/About.js"
import Home from "./pages/Home.js"
import Projects from "./pages/Projects.js"
import { AnimatePresence } from 'framer-motion'
import { BrowserRouter as Switch, Route, useLocation } from "react-router-dom";
function App() {
const location = useLocation();
return (
<div className="App">
<AnimatePresence exitBeforeEnter>
<Switch location={location} key={location.pathname}>
<Route path="/about" component={About} />
<Route path="/projects" component={Projects} />
<Route path="/" exact component={Home} />
</Switch>
</AnimatePresence>
</div>
);
}
export default App;
Home.js (Page File)
import React from 'react';
import '../css/main.css';
import '../css/index.css';
import particleText from '../components/ParticleText.js'
import { Link } from 'react-router-dom';
import { motion } from 'framer-motion'
const pageVariants = {
in: {
opacity: 1,
transition: {
duration: 1
}
},
out: {
opacity: 0,
transition: {
duration: 1
}
}
}
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
try { particleText(true) } catch { /* Error */ }
return (
<motion.div className="main" initial="out" animate="in" exit="out" variants={pageVariants}>
<div className="introOverlay"></div>
<Link to="/about" className="homeButtonContainer">
<p className="homeButtonText">About Me</p>
</Link>
<Link to="/projects" className="homeButtonContainer">
<p className="homeButtonText">My Projects</p>
</Link>
</motion.div>
);
}
}
export default Home;
The property exitBeforeEnter is deprecated now, it must be replaced with mode='wait':
<AnimatePresence mode='wait'>
...
<AnimatePresence>
That way, the change between components will be seamless since the first component will unmount before loading the next one with its respective animations.
Its a bit late but in case you still looking...
The exit animation will NOT take place if AnimatePrecence it self is unmounting from the react tree.
Try this in your App.js :
return (
<Router>
<Route
render={ ({location}) => (
<AnimatePresence initial={ fase } exitBeforeEnter>
<Switch location={ location } key={ location.pathname }>
<Route
exact
path='/'
render={ () => <Home /> }
/>
<Route
exact
path='/projects'
render={ () => <Projects /> }
/>
<Route
exact
path='/about'
render={ () => <About/> }
/>
</Switch>
</AnimatePresence>
) }
/>
</Router>
);
You can leave the callback, render for eg, I just include it for clarity.
The initial={false} is just for disabling the initial animation for subsequent page reload;
If this doesn't work, make sure to keep the same variant structure the same in all your other components.

React Router is showing only one of the Switch components and does nothing when others are called

My routing component looks like this:
import { Link, Route, Switch } from 'react-router-dom';
import Nav from 'react-bootstrap/Nav'
import AllWorkouts from './Workout/AllWorkouts/AllWorkouts';
import WorkoutCreate from './Workout/WorkoutCreate/WorkoutCreate';
import WorkoutDetails from './Workout/WorkoutDetails/WorkoutDetails';
import WorkoutEdit from './Workout/WorkoutEdit/WorkoutEdit';
const Main = () => {
return (
<Switch>
<Route path="/workout/:id/edit" componnet={WorkoutEdit} />
<Route path="/workout/:id/details" componnet={WorkoutDetails} />
<Route path="/workout/create" componnet={WorkoutCreate} />
<Route path="/workout/all" component={AllWorkouts} />
</Switch>
);
}
export default Main;
I have included BrowserRouter in index.js and the only route that is matching is path="/workout/all". I cannot call any of the other routs with Link or directly in the URL.
When I call /workout/all I can see the component with all the other routes nothing happens.
Thank you!
Below is the other component and I do not see any misspelling error:
import { Link, Route, Switch } from 'react-router-dom';
import Button from 'react-bootstrap/Button'
const AllWorkouts = () => {
return (
<div>
<Link to="/workout/create">
<Button variant="outline-primary">Create new workout</Button>{' '}
</Link>
<h1>Hello from AllWorkouts</h1>
</div>
);
}
export default AllWorkouts;
You have misspelled component in the other routes
mport { Link, Route, Switch } from 'react-router-dom';
import Nav from 'react-bootstrap/Nav'
import AllWorkouts from './Workout/AllWorkouts/AllWorkouts';
import WorkoutCreate from './Workout/WorkoutCreate/WorkoutCreate';
import WorkoutDetails from './Workout/WorkoutDetails/WorkoutDetails';
import WorkoutEdit from './Workout/WorkoutEdit/WorkoutEdit';
const Main = () => {
return (
<Switch>
<Route path="/workout/:id/edit" component={WorkoutEdit} />
<Route path="/workout/:id/details" component={WorkoutDetails} />
<Route path="/workout/create" component={WorkoutCreate} />
<Route path="/workout/all" component={AllWorkouts} />
</Switch>
);
}
export default Main;