Hi @drcmda! I'm attempting to use react router and react spring for page transitions but when attemping the solution posted in March I receive the error "Child is not a function". When I add another function after the style the error goes away however the animation does not work.
import React, {Component} from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { Transition, config } from 'react-spring'
import Header from "./components/Header";
import Home from './containers/Home'
import About from './containers/About'
class App extends Component {
render() {
return (
<Router>
<div>
<Header />
<Route
render={({ location }) => (
<Transition
key={location.pathname}
from={{ opacity: 0 }}
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}>
{style => props => (
<Switch location={location}>
<Route exact path="/" render={(props) => <Home style={{...props, style}} />} />
<Route path="/about" render={(props) => <About style={{...props, style}} />} />
</Switch>
)}
</Transition>
)}
/>
</div>
</Router>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You always need items, keys should be an accessor
<Transition
items={location}
keys={location => location.pathname}
from={{ opacity: 0 }}
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}>
{location => style =>(
<Switch location={location}>
<Route exact path="/" render={props => <Home style={{ ...props, style }} />} />
<Route path="/about" render={props => <About style={{ ...props, style }} />} />
</Switch>
)}
</Transition>
location in, keys points to its key, the location that comes out is your target, render that and fill in props. More about transitions, items and so on: http://react-spring.surge.sh/transition
Also make sure to use native later on, especially for routes. http://react-spring.surge.sh/perf
PS. this is reach-router, but it's all the same: https://codesandbox.io/embed/k06o6w6643
I apologize @drcmda. I'm getting quite confused when trying to translate reach-router to react-router. I made the changes put in the code above but it's still not working. Do I need an animated div to perform the animation? Thanks for your help it's much appreciated.
Could you pour your example into a codesandbox? Animated.div is only needed if you use the "native" flag, this is for performance reasons, see the link above.
Here's the sandbox @drcmda https://codesandbox.io/s/3rv5zjo3j5.
You had a typo in there, it's keys, not key. You have several option now, the easiest would probably be just to make a container that you animate, that way you don't have to distribute styles down the tree: https://codesandbox.io/embed/r7qqnqq8x4
If you have subroutes, just do the same, wrap them into a transition, and at this point i would probably make a small component out of this so that you don't duplicate code too much. I've made you one, "AnimatedRoute".
Thanks for the help @drcmda! I have a couple questions when you have the time. First I'm still a little confused on children components and wrapping them with functions if you could recommend somewhere I could read and learn more that would be helpful. Also I'm building an app that uses the Nasa API to show images of the Mars Rovers and was wondering how I would use the Transition element with an array.
They're called render-props, fairly common pattern in react, most libs use them: https://reactjs.org/docs/render-props.html#use-render-props-for-cross-cutting-concerns
Transition is made for arrays, just dump it into items and give keys the right accessor, each image probably has a hash or unique id. More on that here: http://react-spring.surge.sh/transition
I'm working on the slide @drcmda and fed it my array however all the elements are shown at once. Here's the sandbox to show what I have so far, thanks for the help!
Sandbox
Oh, ok, you want to show the current slide only? Then just drop it into items:
items={slides[currentSlide]}
keys={slide => slide.key}
@drcmda I got it to work, I was wondering how to stop the text from jumping up and any suggestions for refactoring to make it simpler and reusable. https://codesandbox.io/s/m4kvxq5n78
If you want the slides to overlay on another you have to make them absolute, quick and dirty way would be:
<Transition
native
items={slides[currentIndex]}
keys={slides => slides.id}
from={{ opacity: 0 }}
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}
>
{item => props => (
<animated.div style={{ position: 'absolute', ...props }}>{item.text}</animated.div>
Or
from={{ position: 'absolute', opacity: 0 }}
Better yet give the animated.div inside a class or make it a styled component. General rule of thumb, transition is just a state machine that retains removed elements. It doesn't do anything out of the ordinary otherwise, how you present items is fully under your control.
@drcmda I've got everything to work and I promise this is my last question. When I click to transition to a new photo the image is sliding to the right and makes the transition look awkward. https://codesandbox.io/s/zk2lm1vn13. You've been a great help and I'll be using Spring for all my projects.
Same thing here,
<Transition
items={marsData[currentIndex]}
keys={marsData => marsData.id}
from={{ position: 'absolute', opacity: 0, zIndex: '500' }}
make sure to give keys a proper key btw, in your box you'd simply channel through the object, it will turn into "[object Object]", but your data has actual id's in them.
@drcmda everything's working now, thanks!
@drcmda I have an question.
If you use styled-components or custom components do: animated(component)
const CustomComponent = styled.div`
...
`
const ReactSpring = animated(CustomComponent)
and
const CustomComponent = styled(animated.div)`
...
`
Which one is the best practice?
It's the same. I'd use the second because it's shorter. What matters most is that eventually animated.el receives an AnimatedValue, and handles from then on the animation by itself.
Most helpful comment
If you want the slides to overlay on another you have to make them absolute, quick and dirty way would be:
Or
Better yet give the animated.div inside a class or make it a styled component. General rule of thumb, transition is just a state machine that retains removed elements. It doesn't do anything out of the ordinary otherwise, how you present items is fully under your control.