react-transition-group icon indicating copy to clipboard operation
react-transition-group copied to clipboard

CSSTransition with react-router doesn't work

Open cjsjyh opened this issue 4 years ago • 4 comments

  const generateRoutes = () =>
    routes.map(route => (
      <Route key={route.path} path={route.path} exact>
        <CSSTransition in={match != null} key={location.key} classNames="page" timeout={500} unmountOnExit>
          <route.component />
        </CSSTransition>
      </Route>
    ))

  return (
    <>
      <div ref={ref}>
        <div className="slide-container">
          <Switch location={location}>{generateRoutes()}</Switch>
        </div>
      </div>
      <Footer />
    </>
  )
.page-enter {
  opacity: 0;
  transform: scale(1.1);
}

.page-enter-active {
  opacity: 1;
  transform: scale(1);
  transition: opacity 300ms, transform 300ms;
}

.page-exit {
  opacity: 1;
  transform: scale(1);
}

.page-exit-active {
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 300ms, transform 300ms;
}

css is the exact copy of the official document and I tried to replicate JSX part as well. routing works fine but there is no animation. What am I doing wrong?

From the issue below, I found out that <TransitionGroup> was causing all the issue so if I can make this work without TransitionGroup, problem will be solved.

cjsjyh avatar Feb 05 '21 15:02 cjsjyh

According to the official documentation, the Switch component does not work when using route animation. You can follow the official documentation example and not use the Switch component!

VitaminCtea avatar Mar 02 '21 05:03 VitaminCtea

@cjsjyh Here's a codesandbox example that I wrote that should be really helpful for you:

  • https://codesandbox.io/s/react-transition-routes-with-noderef-k9q47?file=/src/App.tsx

jordanarldt avatar Oct 19 '21 06:10 jordanarldt

@jordanarldt that seems a nice trick, however that is not valid React. When having the linter in place you should see

React Hook "React.useRef" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.(react-hooks/rules-of-hooks)

Hooks should always define at the top of your component.

I hope this will be fixed in an upcoming release.

reinos avatar Nov 12 '21 10:11 reinos

According to documentation you can't use Switch keyword to work perfectly your CSSTransition. This article explains in detail the reasoning behind it: How to animate transition between react router and routes. (If you need) You can handle render logic of your specific page by checking the route. Does it Confuse you 😶 ?? If it is, don't worry lets see an example....

Suppose you want to render all the pages with CSSTransition and show the NotFound (The 404) page, when no route is matched. This scenario can be implemented like this :

Your routes can be saved in routers.js file like this to organize your code in a better way :

import Home from "../pages/Home";
import About from "../pages/About";
import NotFound from "../pages/NotFound";

export const routes = [
    { path: "/", Component: Home },
    { path: "/about", Component: About },
    { path: "*", Component: NotFound },
]

Your routing logic can be written in App.js file like this :

import { BrowserRouter as Router, Route } from "react-router-dom";
import { CSSTransition } from "react-transition-group";
import { routers } from "./routes/routers";

function App() {
  return (
        <div class="App">
             <Router>
                {routes.map(({path, Component}) => (
                    <Route key={path} exact path={path}>
                    {({ match }) => (
                      <CSSTransition
                        in={match !== null}
                        timeout={400}
                        unmountOnExit
                      >
                        <div className='page'>
                          <Component />
                        </div>
                      </CSSTransition>
                    )}
                  </Route>
                  ))}
             </Router>
        </div>
  );
}
export default App;

Then you ca write a render logic inside your NotFound.js file like :

import { routers } from "../routes/routers";
import { useLocation } from "react-router-dom"; 

const checkIfRouteIsValid = (path) =>  routes.findIndex((route) => route.path === path);

export default function NotFound() {
  const location = useLocation();
  const [show, setShow] = useState(false);

  useEffect(() => { setShow(checkIfRouteIsValid(location.pathname) === -1); }, [location.pathname]);
    return (
      show && <div>Not found!</div>
     );
}

Hope it will help you 😊. If you have any query feel free to ask. THANK YOU.

MizanurRahmann avatar Sep 10 '22 19:09 MizanurRahmann