我一直在使用 React 18 和電影資料庫 (TMDB) API 開發 SPA。
我現在正在Framer Motion的幫助下添加路線之間的轉換(頁面)。
為此,我在 /src
中添加了一個 transition.js
文件,其中包含以下內容:
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;
我使用 import transition from '../../transition'
將上述 transition
匯入到應用程式的元件中,並將匯出的元件包裝在其中。請參閱 Movielist 元件作為範例:
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);
在 App.js 中,我有「正常」路由:
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;
有一個沙箱,程式碼為這裡。
將 export default myComponent
改為 export default transition(myComponent)
會使元件無法渲染。
這樣做...
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 } }} /> </> ); };
拋出此錯誤:
請求失敗,狀態代碼 404 AxiosError:請求失敗 狀態碼404 解決時(http://localhost:3000/static/js/bundle.js:63343:12) 在 XMLHttpRequest.onloadend (http://localhost:3000/static/js/bundle.js:62034:66)
在嘗試新增平滑的頁面過渡之前,一切都工作正常。
發生錯誤是因為從
transition
函數傳回的函數沒有渲染元件;它傳回undefined
相反。要解決此問題,您可以刪除大括號或為內部函數定義明確傳回:
明確傳回
#我認為您想要的(看起來這就是您想要做的,幹得好!)是創建一個
高階元件
將您的頁面元件包裝在framermotion 的code>motion.div,以便它可以為您轉換您的元件。嘗試將您的
轉換
程式碼變更為:然後,您可以透過將頁面元件作為
TransitioningComponent
參數傳遞給withTransition
並從 jsx 檔案中匯出來呼叫它。在此處查看工作程式碼沙箱
這是它的實際操作的 gif
您不斷從 axios 收到的
404
錯誤是由於codesandbox.env
檔案中儲存的 API 金鑰過期所致。我認為查詢失敗是由於 403 - 存取被拒絕回應。我沒有檢查,但這對我來說最有意義。我註解掉了一些 axios 調用,以便您可以看到轉換的工作情況。希望這個答案對您有幫助!