是什么导致在这个 React 18 应用程序中使用 transition(myComponent) 失败?
P粉717595985
P粉717595985 2024-03-28 19:34:04
0
2
353

我一直在使用 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)

在尝试添加平滑的页面过渡之前,一切都工作正常

问题

  1. 我做错了什么?
  2. 解决此问题最可靠的方法是什么?

P粉717595985
P粉717595985

全部回复(2)
P粉432930081

发生错误是因为从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 />
      </>
    )

  }
}
P粉764003519

我认为您想要的(看起来这就是您想要做的,干得好!)是创建一个 高阶组件 将您的页面组件包装在 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 文件中导出来调用它。

// Movielist.jsx line 41
export default withTransition(Movielist);

此处查看工作代码沙箱

这是它的实际操作的 gif

您不断从 axios 收到的 404 错误是由于codesandbox .env 文件中存储的 API 密钥过期所致。我认为查询失败是由于 403 - 访问被拒绝响应。我没有检查,但这对我来说最有意义。我注释掉了一些 axios 调用,以便您可以看到转换的工作情况。

希望这个答案对您有所帮助!

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!