What causes transition(myComponent) to fail in this React 18 application?
P粉717595985
P粉717595985 2024-03-28 19:34:04
0
2
364

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;

Sandbox

There is a sandbox, the code is here.

question

Changing export default myComponent to export default transition(myComponent) will make the component unable to render.

edit

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 .

question

  1. What did i do wrong?
  2. What is the most reliable way to solve this problem?

P粉717595985
P粉717595985

reply all(2)
P粉432930081

The error occurs because the function returned from the transition function does not render the component; it returns undefined instead.

const transition = (OgComponent) => {
  // the function below does not return the component
  return () => {
    <>
      <OgComponent />
      ...
    </>
  }
}

To solve this problem, you can remove the curly braces or define an explicit return for the inner function:

Explicit return

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

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:

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;
};

You can then call it by passing the page component as the TransitioningComponent parameter to withTransition and export it from a jsx file.

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

View working code sandbox here

This is a gif of it in action

The

404 error you keep getting from axios is due to an expired API key stored in the codesandbox .env file. 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.

Hope this answer is helpful to you!

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template