I have been developing a SPA using React 18 and the Movie Database (TMDB) API.
I am now adding transitions between routes(pages) with the help of Framer Motion.
To do this, I added a transition.js
file in /src
with the following content:
import { motion } from "framer-motion"; const transition = (OgComponent) => { return () => { <> <OgComponent /> <motion.div className="slide-in" initial={{ opacity: 0, x: '-100px' }} animate={{ opacity: 1, x: 0, transition: { duration: 0.3 } }} exit={{ opacity: 0, x: 0, transition: { duration: 0.3 } }} > <motion.div /> </> } } export default transition;
I use import transition from '../../transition'
to import the above transition
into a component of the application and wrap the exported component in it. See the Movielist component as an example:
import { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; import axios from 'axios'; import Moviecard from '../Moviecard/Moviecard'; import transition from '../../transition'; function Movielist({ page_title, listMovies }) { const API_URL = 'https://api.themoviedb.org/3'; const location = useLocation(); const [movies, setMovies] = useState([]); const getMovies = async () => { const { data: { results } } = await axios.get(`${API_URL}/movie/${listMovies}`, { params: { api_key: process.env.REACT_APP_API_KEY } }); setMovies(results); } const displayMovies = () => { return movies.map(movie => ( <Moviecard key={movie.id} movie={movie} /> )) } useEffect(() => { getMovies(); }, [location]) return ( <> <h1 className="page-title">{ page_title }</h1> <div className="row movie-list"> { displayMovies() } </div> </> ); } export default transition(Movielist);
In App.js I have the "normal" route:
import { Routes, Route } from 'react-router-dom'; import Topbar from './components/Topbar/Topbar'; import Footer from './components/Footer/Footer'; import Movielist from './components/Movielist/Movielist'; import Moviedetails from './components/Moviedetails/Moviedetails'; import Actordetails from './components/Actordetails/Actordetails'; function App() { return ( <div className="App"> <Topbar /> <div className="container"> <Routes> <Route path="/" element={<Movielist page_title="Now playing" listMovies="now_playing" />} /> <Route path="/top-rated" element={<Movielist page_title="Top rated" listMovies="top_rated" />} /> <Route path="/movie/:id" element={<Moviedetails />} /> <Route path="/actor/:id" element={<Actordetails />} /> </Routes> </div> <Footer /> </div> ); } export default App;
There is a sandbox, the code is here.
Changing export default myComponent
to export default transition(myComponent)
will make the component unable to render.
this way...
const transition = (OgComponent) => { return () => ( <> <OgComponent /> <motion.div className="slide-in" initial={{ opacity: 0, x: 0 }} animate={{ opacity: 1, x: 100, transition: { duration: 0.5 } }} exit={{ opacity: 0, x: 0, transition: { duration: 0.5 } }} /> </> ); };
Throws this Error :
Request failed, status code 404 AxiosError: Request failed Status code 404 When resolved (http://localhost:3000/static/js/bundle.js:63343:12) In XMLHttpRequest.onloadend (http://localhost:3000/static/js/bundle.js:62034:66)
Everything was working fine until I tried to add a smooth page transition .
The error occurs because the function returned from the
transition
function does not render the component; it returnsundefined
instead.To solve this problem, you can remove the curly braces or define an explicit return for the inner function:
Explicit return
I think what you want (it looks like that's what you want to do, good job!) is to create a
Higher Order Component
that wraps your page component in framermotion of code>motion.div so that it can transform your component for you.Try changing your
conversion
code to:You can then call it by passing the page component as the
TransitioningComponent
parameter towithTransition
and export it from a jsx file.View working code sandbox here
This is a gif of it in action404
Hope this answer is helpful to you!error you keep getting from axios is due to an expired API key stored in the codesandbox
.envfile. I think the query failed due to a 403 - Access Denied response. I haven't checked, but this makes the most sense to me. I've commented out some of the axios calls so you can see the transformation working.