Animating route transitions with CSSTransitionGroup and React-Router v6 - javascript

I'm starting to use React-Router v6, and running into issues animating route transitions.
Both the react-router docs and the react-transition-group docs specify ways that are not compatible with the new v6 api.
The primary reason seems to be the removal of the <Switch> component.
In react-router#v5, this worked:
import { Router, Route, Switch, useLocation } from 'react-router#v5'
import { TransitionGroup, CSSTransition } from 'react-transition-group'
function App() {
const location = useLocation();
return (
<Router>
<TransitionGroup>
<CSSTransition key={location.key} classNames="fade" timeout={300}>
<Switch location={location}>
<Route path="/a" children={<A />} />
<Route path="/b" children={<B />} />
</Switch>
</CSSTransition>
</TransitionGroup>
</Router>
);
}
...However, in react-router#v6, this does not work:
function App() {
const location = useLocation();
return (
<Router>
<TransitionGroup>
<CSSTransition key={location.key} classNames="fade" timeout={300}>
<Routes location={location}>
<Route path="/a" element={<A />} />
<Route path="/b" element={<B />} />
</Routes>
</CSSTransition>
</TransitionGroup>
</Router>
);
}
It seems that the main difference is how <Switch> accepted the Location prop, and would keep both routes rendered long enough for the transtion to conclude.
Without that, it seems like route entrance animations are abrupt. Interesting, exit animations from nested routes appears to work correctly.
Any ideas how to get transition animations working with react-router v6?

It seems you want both respective components on screen at the same time; that is, the new component would be animating in while the old is animating out.
This was impossible before v6.0.0-beta.3.
But it is now possible (after v6.0.0-beta.3) thanks to the re-addition of the location prop to the <Routes> component. (release notes for v6.0.0-beta.3)
Your sample code only needs 2 modifications to work for react-router#v6-beta.3, but needs the 3rd modification for the react-router#v6:
<Router> should instead web compatible router, like <BrowserRouter>.
The useLocation() hook must be used in the context of a router component. To fix that, you need a router wrapped in a parent component first, and then you're able to use the hook in any of router's child components.
Replace the children prop with the element prop, otherwise you'll get an error saying all component children of <Routes> must either be a <Route> or <React.Fragment>.
Also – helpful to know for animated routes - "<TransitionGroup> renders a <div> by default" which can sometimes mess with animations. So it's helpful to pass component={null} in props to stop it from doing that.
DEMO: All these changes are available here in this codesandbox:

There has been changes with react-router-v6. Read here and here
To get your animation working, replace Switch with Routes (no need to provide location). Provide element prop to Route. Also install history library.
I have made a working demo using v6. Both entering and leaving animations are working. Compare the code with yours.

In the meantime, this issue was fixed.
The issue was mentioned here here.
See a working code example here: here.

Related

Blank page and the console showing me error message about routes [duplicate]

Here is the code screenshot.
I want to render Homepage component but I want to wrap it into these MainLayout component.
The problem is that screen is blank and there is no error in Terminal but when I inspect the page it says "Matched leaf route at location "/" does not have an element", so guys I know this is version update syntax problem because I had same problem when I was writing component= {component } but syntax has been changed and I should have written element={<component />}.
So I believe this is also syntax problem but I've done research but couldn't solve. I believe I should change this
/* ... */ render = {() => (
<MainLayout>
<Homepage />
</MainLayout>
)}
somewhat into newer syntax but don't know how.
The Route components in react-router-dom v6 no longer take component or render props; the routed components are rendered on the element prop as JSX.
<Routes>
...
<Route
path="/"
element={(
<MainLayout>
<Homepage />
</MainLayout>
)}
/>
...
</Routes>

Matched leaf route at location "/" does not have an element react-router [duplicate]

Here is the code screenshot.
I want to render Homepage component but I want to wrap it into these MainLayout component.
The problem is that screen is blank and there is no error in Terminal but when I inspect the page it says "Matched leaf route at location "/" does not have an element", so guys I know this is version update syntax problem because I had same problem when I was writing component= {component } but syntax has been changed and I should have written element={<component />}.
So I believe this is also syntax problem but I've done research but couldn't solve. I believe I should change this
/* ... */ render = {() => (
<MainLayout>
<Homepage />
</MainLayout>
)}
somewhat into newer syntax but don't know how.
The Route components in react-router-dom v6 no longer take component or render props; the routed components are rendered on the element prop as JSX.
<Routes>
...
<Route
path="/"
element={(
<MainLayout>
<Homepage />
</MainLayout>
)}
/>
...
</Routes>

React-Router-Dom: Difference between using component inside route synax vs. using /* component={componentName} */ syntax?

I am new to React and I have seen two different syntaxes for routing using react-router-dom, as illustrated below with Example1 and Example2. Welcome is just a standard react component.
Example1:
<BrowserRouter>
<Switch>
<Route exact path="/"><Welcome /></Route>
</Switch>
</BrowserRouter>
Example2:
<BrowserRouter>
<Switch>
<Route exact path="/" component={Welcome} />
</Switch>
</BrowserRouter>
Is there any difference between the two syntaxes? As of 2021 is there a preference?
The documentation already answers this for you:
When you use component (instead of render or children) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop.

react-router-redux redirect to absolute url

I'm migrating a react application and I'm trying to split it. Basically, I would like to redirect some client-side react routes to absolute urls (or relative, but at least go with a server roundtrip, where reverse proxying is done)
Note that
react-router 3.0.0
react-router-redux 4.0.7
The app have these urls
http://myhost/ => homepage
http://myhost/someroute1 => a first route
http://myhost/someroute2 => a second route
http://myhost/someroute3 => a third route
Everything is inside react right now.
Routing looks like this :
<Provider store={store}>
<Router history={history}>
<Route path="/" component={Root}>
<IndexRoute component={Home} />
<Route path="/someroute1" component={Route1} />
<Route path="/someroute2" component={Route2} />
<Route path="/someroute3" component={Route3} />
</Route>
</Router>
</Provider>
The goal is to redirect, say, routes "/" and "/someroute2" to static urls (server urls). As so :
http://myhost/ => http://anotherhost/
http://myhost/someroute1 => keep react routing
http://myhost/someroute2 => http://anotherhost/anotherroute5
http://myhost/someroute3 => keep react routing
The question is simple : is is possible to replace, in a clean way, a react router route with an absolute url ?
I heard about Redirect and IndexRedirect components, but I can't figure how to use it properly, and, due to a lack of react / react-router, I can't figure if there would be any dangerous side-effects (in history for example).
Use Route's render prop instead of component. That way, you can specify a function to be called instead of a component to be instantiated. In the function, perform the navigation the old-fashioned way, using window.location.href:
<Route
path="/someroute2"
render={() => {
window.location.href = "http://anotherhost/anotherroute5";
return null;
}}
/>
Partially based on #brub answer, I've found a solution using a dumb component.
import React, { Component } from 'react'
export default class MyRedirectRoute extends Component {
componentDidMount() {
window.location.href = //my url here
}
render() {
return null
}
}
That I pass like this
<Route path="/someroute3" component={MyRedirectRoute} />
Though, I'm still not aware of a few things :
Is this a recommended solution ?
Are there any history side-effect ?
Is there any better (more react-router) solution than window.location.href ? I tried this.context.history without any success...
I'm waiting for feedback / better solution before accepting my own answer
You probably don't need React Router for this. The creator of React Router suggests using the <a> tag.
I haven't tried it but syntactically you could do it like this:
<Route
path="/someroute2"
render={() => <Redirect to="http://anotherhost/anotherroute5" />}
/>

React show information from one component to another that don't have common parant

I have the following react router:
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={MyHeader}>
<IndexRoute component={Main}/>
<Route path="carwash" component={CarWashPage} />
<Route path="carwashAdd" component={AddCarWashPage} />
<Route path="carwashAdd/:carWashId" component={EditCarWashPage} />
</Route>
</Router>,
destination
);
In component AddCarWashPage I have a form for carWash and when it is submitted I make redirection (browtherHistory.push('/carwash')) to component CarWashPage.
Now afte redirection I want to show in component CarWashPage information that carwash was save succesfully. How can I pass this text or maybe some flag from AddCarWashPage to CarWashPage that CarWashPage may to know when the correcsponding text has to be shown ?
The simple solution is Redux. If you're not looking to add this library, then you need to have either a global state bus (could get messy) or a common ancestor. Both of those routes are children to MyHeader. If you'd like to use the common ancestor approach then you could have MyHeader pass down a callback to the child.
Redux is still the way to go though so I highly recommend it.

Categories

Resources