Using React SwitchTransition with Mount and Unmount Components - reactjs

When mounting a component with a routing path I want to trigger a CSSTransition. My goal is to have the Component which is about to be unmounted persist long enough for the mounting component to fully transition in.
An analog equivalency would be sliding two cards over each other and only then remove the obscured/hidden card below.
import {
Switch,
BrowserRouter,
Route,
Redirect,
useLocation,
} from 'react-router-dom';
import {
CSSTransition,
TransitionGroup,
SwitchTransition,
} from 'react-transition-group';
import NavBar from './jsx/NavBar';
import Home from './jsx/Home';
import SomePage from './jsx/SomePage';
function App() {
let location = useLocation();
return (
<div className='App'>
<NavBar />
<TransitionGroup>
<SwitchTransition mode='in-out'>
<CSSTransition
key={location.key}
classNames='slide'
timeout={{
enter: 0,
exit: 500,
}}
>
<Switch>
<Route path='/' exact>
<Redirect to='/home' />
</Route>
<Route path='/home' component={Home} exact />
<Route path='/page' component={SomePage} />
</Switch>
</CSSTransition>
</SwitchTransition>
</TransitionGroup>
</div>
);
}
.navbar {
width: 100%;
position: fixed;
top: 0;
z-index: 99;
}
.home {
height: 100vh;
.some-page {
height: 100vh;
width: 100%;
transform: translateY(100vh);
background-color: red;
}
.animate {
position: absolute;
z-index: 1;
top: 0;
transition: transform 0.75s ease-in;
overflow: hidden;
}
.slide-enter-done {
transform: translateY(0vh);

Related

React-router page transition animation

I am trying to create a transition effect between pages using react-router-dom. I am trying to delay the rendering of the routes component, but it doesn't seem to work.
I have the following code
const App = () => {
const location = useLocation();
const [displayLocation, setDisplayLocation] = useState(location);
const [transitionStage, setTransitionStage] = useState("slideIn");
useEffect(() => {
if (location !== displayLocation) setTransitionStage("slideOut");
}, [location, displayLocation]);
return (
<>
<Layout>
<ScrollToTop />
<TransitionAnimation
transitionStage={transitionStage}
onAnimationEnd={() => {
if (transitionStage === "slideIn") {
setTransitionStage("slideOut");
setDisplayLocation(location);
}
}}>
</TransitionAnimation>
<Routes location={displayLocation}>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Layout>
</>
);
};
export default App;
const TransitionAnimation = styled.div`
width: 0px;
height: 100vh;
background: #000000;
position: fixed;
top:0;
left:0;
bottom:0;
right: 0;
z-index: 0;
animation: ${(props) => props.transitionStage} 1s linear;
#keyframes slideIn {
from {
width: 0%;
}
to {
width: 90%;
}
}
#keyframes slideOut {
from {
right: 0%;
}
to {
right: -10000px;
}
}
`;
I have tried the above code, but it doesn't change the component even if the route changes.
Please what better way can I achieve this.

using react-router-dom Link with styled components renders nothing

I am using styled-components for the first time and facing some issue while using Link form react-router-dom v6.
Nothing is rendered with the current code but when I remove the Link tag code works fine. Please help.
import styled from "styled-components";
import { Link } from "react-router-dom";
const Home = () => {
return (
<Link to="/">
<HomeButton>Place Order</HomeButton>
</Link>
);
};
const HomeButton = styled.button`
color: black;
font-weight: bold;
font-family: "Space Grotesk", sans-serif;
font-size: 1.2rem;
background-color: white;
height: 45px;
border-radius: 5px;
width: 86%;
margin-left: 7%;
margin-right: 7%;
margin-top: 20px;
-webkit-box-shadow: -1px 0px 2px 2px rgba(99, 99, 99, 1);
`;
export default Home;
react router dom v6 requires your navabar component and <Route path= element={}/> if you need to use link.
<Router >
<Navbar/>
<Routes>
<Route path="/" element={<div><h1>Home Page</h1></div>}/>
<Route path="register" element={<RegisterPage />} />
<Route path="login" element={<LoginPage />} />
</Routes>
</Router>

CSS modules are "undefined" on navigation bar that uses react-router-dom

I'm making a react app that had a successful navigation bar built on react-router. I used CSS modules to compartmentalize the styling which helped. I messed around with React-PDF and after having removed it from my code, my navigation bar now no longer displays properly. It only displays one link and on dev tools, the CSS for the navigation bar and components within it are "undefined". I'd like to know how to revert this back to normal.
Below is my code.
Nav.js
import React from 'react';
import { BrowserRouter as NavLink } from 'react-router-dom';
import navstyles from './navstyles.module.css';
function Nav() {
return (
<div>
<nav className={`${navstyles.navbar}`}>
<h2 className={`${navstyles.navboxhome}`}>
<NavLink
exact to="/"
activeStyle={{
fontWeight: "bold",
color: "blue"
}}
>
Home
</NavLink>
</h2>
<h2 className={`${navstyles.navboxstories}`}>
<NavLink
exact to="/stories"
activeStyle={{
fontWeight: "bold",
color: "blue"
}}
>
Stories
</NavLink>
</h2>
<h2 className={`${navstyles.navboxcontact}`}>
<NavLink
exact to="/contact"
activeStyle={{
fontWeight: "bold",
color: "blue"
}}
>
Contact
</NavLink>
</h2>
</nav>
</div>
);
};
export default Nav;
navstyles.module.css
.navbar {
display: grid;
width: 100%;
height: 10vh;
grid-template-columns: repeat(3, 1fr);
}
[class^="navbox"] {
background-color: greenyellow;
border-radius: 1px;
border-color: black;
border: 2px;
border-style: solid;
display: grid;
/* To place the letter at the center */
place-items: center;
}
.navboxhome {
background-color: skyblue;
display: grid;
place-items: center;
}
.navboxstories {
background-color: skyblue;
display: grid;
place-items: center;
}
.navboxcontact {
background-color: skyblue;
display: grid;
place-items: center;
}
App.js
import './App.css';
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Nav from './Components/Nav';
import Footer from './Components/Footer';
import Stories from './Pages/Stories';
import Contact from './Pages/Contact';
function App() {
return (
<Router>
<div className="container">
<div className="navigation">
<Nav />
</div>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/stories" exact component={Stories} />
<Route path="/contact" exact component={Contact} />
</Switch>
<div className="bottom">
<Footer />
</div>
</div>
</Router>
);
}
const Home = () => (
<div className="subcontainer">
<div className="box-2">B</div>
<div className="box-3">C</div>
<div className="box-4">D</div>
<div className="box-5">E</div>
<div className="box-6">F</div>
</div>
);
export default App;
In nav.js, replace the
import { BrowserRouter as NavLink } from 'react-router-dom';
with
import { NavLink } from 'react-router-dom';
Because BrowserRouter is not used to create a link, instead it is used to wrap your application so that you can use navigation component in react-routed-dom (eg. NavLink or Link).
https://reactrouter.com/web/api/BrowserRouter

How can i render a route component in the parent component from a child component

Suppose i have navigation bar component
<Nav />
I have all the routing logic inside this navigation bar component
When i click on a link the navigation happens but the component is loaded inside the navigation bar and not outside.
this is a image from http://localhost:3000/whiteboard , the whiteBoard component should render from root component where the logic of router is not written.check this Codesanbox to view the full code and working .
You have to move <Switch> ... </Switch> to app.js at the same level as <Nav />.
nav.js
import React from "react";
import styled from "styled-components";
import { Link } from "react-router-dom";
const NavBar = styled.nav`
width: 20vw;
border: black 1px solid;
height: 100vh;
`;
const AppName = styled.h1`
padding: 1em;
`;
const ListContainer = styled.ul``;
const ListItem = styled.li``;
const Nav = () => {
return (
<NavBar>
<AppName>Test</AppName>
<ListContainer>
<ListItem>
<Link to="/">Draft</Link>
</ListItem>
<ListItem>
<Link to="/notes">Notes</Link>
</ListItem>
<ListItem>
<Link to="/whiteboard">Whiteboard</Link>
</ListItem>
</ListContainer>
</NavBar>
);
};
export default Nav;
App.js
import Nav from "./components/nav";
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
function App() {
return (
<div className="App">
<Router>
<Nav />
<Switch>
<Route path="/notes" component={Draft} />
<Route path="/whiteboard" component={Whiteboard} />
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
</div>
);
}
function Home() {
return <h2>Home</h2>;
}
function Whiteboard() {
return <h2>Whiteboard</h2>;
}
function Draft() {
return <h2>Draft</h2>;
}
export default App;
index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.App {
display: flex;
}
You should move the <Switch> statement with all the routes outside the <Nav/> component. It's not supposed to be in the navigation. In order for this to work, you should also make <Router> top-level (so that both <Switch/> and <Link/> are below the Router component so that they can access it's context), like this:
function App() {
return (
<Router>
<div className="App">
<Nav />
<Switch>
...
</Switch>
</div>
</Router>
);
}

React Router url updates but component does not

Someone plese help, I am unabe to find errors in my code that led the react-router-dom into not working. When I click on any link, URL changes but view doesn't. I've read more than 40 threads and done research but I am unable to find my mistake by my own.
The App.js file
import React, { useEffect } from 'react';
import { BrowserRouter as Router, Switch, Route, Redirect, Link } from 'react-router-dom';
import Header from '../components/Header.component';
import Contact from '../pages/Contact.page';
import DivineShop from '../pages/DivineShop.page';
import Events from '../pages/Events.page';
import Forums from '../pages/Forums.page';
import Home from '../pages/Home.page';
import Sadhanas from '../pages/Sadhanas.page';
let App = (props) => {
useEffect(() => {
document.querySelector('#body').style.backgroundColor = '#eee';
document.querySelector('#body').style.color = '#444';
document.querySelector('#body').style.fontFamily = 'aladin';
document.querySelector('#body').style.fontSize = '18px';
},[])
return (
<>
<Header />
<Router>
<Switch>
<Route path='/' exact component={Home} />
<Route path='/forums' exact component={Forums} />
<Route path='/events' exact component={Events} />
<Route path='/sadhanas' exact component={Sadhanas} />
<Route path='/divineshop' exact component={DivineShop} />
<Route path='/contact' exact component={Contact} />
<Redirect to='/'/>
</Switch>
</Router>
</>
);
}
export default App;
The header Component
import React from 'react';
import styled from 'styled-components';
import Nav from './Nav.component';
const HeroSection = styled.section`
background-image: url(${props => props.backgroundImage});
height: 70vh;
width: 100vw;
`;
const Header = (props) => {
return (
<header>
<Nav />
<HeroSection backgroundImage={props.backgroundImage}/>
</header>
);
}
export default Header
The Nav Component
import React, { useState } from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
import styled from 'styled-components';
import colors from '../configs/colors';
import Logo from '../images/Logo.svg';
import { FaBars } from 'react-icons/fa';
import { GrClose } from "react-icons/gr";
const StyledLink = styled(Link)`
text-decoration: none;
margin-bottom: .5em;
color: ${colors.black};
padding: .5em;
transition: all .3s ease-in;
`;
const StyledMenus = () => (
<Router>
<>
<StyledLink to='/'>Home</StyledLink>
<StyledLink to='/forums'>Forums</StyledLink>
<StyledLink to='/events'>Events</StyledLink>
<StyledLink to='/sadhanas'>Sadhanas</StyledLink>
<StyledLink to='/divineshop'>Divine Shop</StyledLink>
<StyledLink to='/contact'>Contact</StyledLink>
</>
</Router>
);
const MobileNav = styled.nav`
display: flex;
flex-direction: column;
flex-wrap: wrap;
aligh-items: flex-start;
width: 40%;
position: absolute;
left: 1em;
top: 3.5em;
box-shadow: -5px -5px 5px #f9f9f9, 5px 5px 5px #ccc;
border-radius: 20px;
padding: .5em .2em;
display: ${props => props.visibility ? 'flex' : 'none'};
#media screen and (min-width: 550px){
display: none;
}
& *:hover {
padding-left: 2em;
background: ${colors.chineseYellow};
color: ${colors.queenBlue};
}
& *:first-child {
border-radius: 10px 10px 0 0;
}
`;
const HighResNav = styled.nav`
display: flex;
flex-direction: row;
flex: 1 1 70%;
justify-content: space-evenly;
#media screen and (max-width: 550px){
display: none;
}
& * {
border-bottom: 2px solid ${colors.white};
}
& *:hover{
color: ${colors.queenBlue};
border-bottom-color: ${colors.queenBlue};
}
`;
const StyledFaBars = styled(FaBars)`
cursor: pointer;
font-size: 1.2em;
flex: 0 0 auto;
&:hover{
color: ${colors.queenBlue}
}
#media screen and (min-width: 550px){
display: none;
}
`;
const StyledGrClose = styled(GrClose)`
cursor: pointer;
font-size: 1.2em;
flex: 0 0 auto;
&:hover{
color: ${colors.queenBlue}
}
#media screen and (min-width: 550px){
display: none;
}
`;
const NavContainer = styled.section`
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 1em 2em;
justify-content: space-between;
align-items: center;
`;
const Nav = () => {
const [mobileMenuVisibility, setMobileMenuVisibility] = useState(false);
const handleBarClick = () => {
console.log(mobileMenuVisibility);
setMobileMenuVisibility(!mobileMenuVisibility);
}
return (
<NavContainer>
{mobileMenuVisibility ? <StyledGrClose onClick={handleBarClick} /> : <StyledFaBars onClick={handleBarClick} />}
<img src={Logo} alt="Main-Logo" />
<HighResNav>
<StyledMenus />
</HighResNav>
<MobileNav visibility={mobileMenuVisibility ? "true" : undefined}>
<StyledMenus />
</MobileNav>
</NavContainer>
)
}
export default Nav;
Every page have this structure
import React from 'react';
import {withRouter} from 'react-router-dom';
const Contact = () => {
return (
<div>
Hello from contact page
</div>
)
}
export default withRouter(Contact);
Please help
I suspect the issue is that you have two distinct Router components. They are not linked in any way - changing the url in one will not propagate that change to the Switch in the other. Remove the second Router from the StyledMenus component, and move the Header component inside the original Router in App.js.
<Router>
<Header />
<Switch>
<Route path='/' exact component={Home} />
<Route path='/forums' exact component={Forums} />
<Route path='/events' exact component={Events} />
<Route path='/sadhanas' exact component={Sadhanas} />
<Route path='/divineshop' exact component={DivineShop} />
<Route path='/contact' exact component={Contact} />
<Redirect to='/'/>
</Switch>
</Router>

Resources