我一直在使用 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)
在尝试添加平滑的页面过渡之前,一切都工作正常。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
发生错误是因为从
transition函数返回的函数没有渲染组件;它返回undefined相反。const transition = (OgComponent) => { // the function below does not return the component return () => { <> <OgComponent /> ... </> } }要解决此问题,您可以删除大括号或为内部函数定义显式返回:
显式返回
const transition = (OgComponent) => { return () => { 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 } }} /> <motion.div /> </> ) } }我认为您想要的(看起来这就是您想要做的,干得好!)是创建一个
高阶组件将您的页面组件包装在 framermotion 的 code>motion.div,以便它可以为您转换您的组件。尝试将您的
转换代码更改为:import React from "react"; import { motion } from "framer-motion"; export const withTransition = (TransitioningComponent) => { class WithTransition extends React.Component { render() { return ( <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.5 } }} > <TransitioningComponent {...this.props} /> </motion.div> ); } } WithTransition.displayName = `WithTransition(${ TransitioningComponent.displayName || TransitioningComponent.name })`; return WithTransition; };然后,您可以通过将页面组件作为
TransitioningComponent参数传递给withTransition并从 jsx 文件中导出来调用它。在此处查看工作代码沙箱
这是它的实际操作的 gif
您不断从 axios 收到的
404错误是由于codesandbox.env文件中存储的 API 密钥过期所致。我认为查询失败是由于 403 - 访问被拒绝响应。我没有检查,但这对我来说最有意义。我注释掉了一些 axios 调用,以便您可以看到转换的工作情况。希望这个答案对您有所帮助!