(React) 使用 Framer-Motion 页面转换的 Lazy Loading 组件
(React) Lazy Loading components that use Framer-Motion page transitions
向上、向下和横向寻找解决此问题的方法。
我的目标是将延迟加载分配给我的 React 网站中的几乎所有组件。但是,当这些组件进入和退出时,这些组件会利用 framer-motion 页面转换。页面转换和延迟加载的组合导致组件在作为路由单击时不再正确加载。
我从这个 post (https://github.com/reactjs/react-transition-group/issues/580) and tried to introduce the "react-lazy-with-preload" package (https://github.com/ianschmitz/react-lazy-with-preload) 中找到了灵感,但是我没能成功。
有人知道这个问题的解决方案吗?我肯定不是唯一一个尝试对使用具有成帧运动页面转换组件的 React 网站进行数据拆分的人。
App.js 代码如下:
import React, { Suspense } from 'react';
import { Switch, Route, useLocation } from 'react-router-dom';
import lazy from "react-lazy-with-preload";
import { AnimatePresence } from 'framer-motion';
////////////////////////////////////////////////
//PREPARE PAGES OF WEBSITE AS LAZY LOADED PAGES
import Navbar from './components/layout/Navbar/Navbar';
import Footer from './components/layout/Footer/Footer';
import Home from './components/layout/Homepage/Home';
const Dashboard = lazy(() => import('./components/dashboard/Dashboard'));
const Login = lazy(() => import('./components/authorization/login/LoginComponent'));
const SignUp = lazy(() => import('./components/authorization/signup/SignupComponent'));
const OurTeam = lazy(() => import( './components/layout/OurTeam/OurTeam'));
function App () {
let location = useLocation();
//Trying to preload the components which contain Page-Transitions
OurTeam.preload();
Login.preload();
SignUp.preload();
Dashboard.preload();
return (
<div className='page-container'>
<div className='content-wrap'>
<Navbar />
<AnimatePresence exitBeforeEnter> {/* Exit page transition occurs before next page loads. */}
<ScrollToTop/> {/* Causes the screen to scroll to the top after routing occurs. */}
<Switch location={location} key={location.pathname}> {/* Switch is used to make sure only 1 route is loaded up at a time. location and key are used for page transition animation.*/}
{/*Homepage will not be data-split and will always be loaded */}
<Route exact path='/' component={Home} />
<Suspense fallback='Loading...'>
<Route path='/OurTeam' component={OurTeam} />
</Suspense>
<Suspense fallback='Loading...'>
<Route path='/dashboard' component={Dashboard}/>
</Suspense>
<Suspense fallback='Loading...'>
<Route path='/login' component={Login} />
</Suspense>
<Suspense fallback='Loading...'>
<Route path='/signup' component={SignUp} />
</Suspense>
</Switch>
</AnimatePresence>
</div>
<Footer/>
</div>
);
//}
}
export default App;
未来读者的问题答案
在查阅了大量资源和其他教程后,我找到了解决我遇到的问题的方法。
简而言之,而不是在“App.js”中的路由处延迟加载组件(如上面问题中的代码所示)我决定在 Route 标记的每个组件内部延迟加载正在打电话。这是可行的,因为这些路由实际上会转到组件,这些组件将根据用户屏幕宽度加载非常特定的页面(请参阅下面的示例代码以获取我的注册页面):
SignupComponent.js 延迟加载前
import * as React from 'react';
import { useState, useEffect } from 'react';
import { connect } from 'react-redux'; //The library that holds react and redux together.
import { Redirect } from 'react-router-dom'; //Used to redirect logged out users to a different page.
import '../authorization.css'
//Page Transition imports
import { PageTransition } from '../../layout/PageTransition';
import {motion} from 'framer-motion';
import SignupFullscreen from './SignupFullscreen';
import SignupSmallFullscreen from './SignupSmallFullscreen';
import SignupTablet from './SignupTablet';
import SignupSmallTablet from './SignupSmallTablet';
import SignupMobile from './SignupMobile';
const SignupComponent = (props) => {
const { authToken, auth } = props
//Using the useWindowSize function to determine width of screen.
let [width] = useWindowSize();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//FULLSCREEN.
if(width >= 1425){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupFullscreen/>
</motion.div>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SMALL FULLSCREEN.
else if( (width>1100)&&(width<=1425) ){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupSmallFullscreen/>
</motion.div>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//FULL TABLET SCREEN.
else if( (width>650)&&(width<=1100) ){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupTablet/>
</motion.div>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//HALF TABLET SCREEN.
else if( (width>425)&&(width<=650) ){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupSmallTablet/>
</motion.div>
);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MOBILE SCREEN.
else if( width<=425 ){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupMobile/>
</motion.div>
);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//DEFAULT IS FULLSCREEN
else {
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupFullscreen/>
</motion.div>
);
}
}
const mapStateToProps = (state) => {
return {
authToken: state.auth.authToken,
authError: state.auth.authError,
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return {
}
}
//Used to determine width of the screen.
function useWindowSize() {
const [size, setSize] = useState([window.innerWidth]);
useEffect(() => {
const handleResize = () => {
setSize([window.innerWidth]);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
}
}, []);
return size;
}
export default connect(mapStateToProps, mapDispatchToProps)(SignupComponent)
要引入延迟加载,只需将这些组件中的每一个包装在 标记内,如下面的代码所示。
SignupComponent.js 添加延迟加载后
import * as React from 'react';
import { useState, useEffect } from 'react';
import { connect } from 'react-redux'; //The library that holds react and redux together.
import { Redirect } from 'react-router-dom'; //Used to redirect logged out users to a different page.
import '../authorization.css'
//Page Transition imports
import { PageTransition } from '../../layout/PageTransition';
import {motion} from 'framer-motion';
const SignupComponent = (props) => {
const SignupFullscreen = React.lazy(() => import('./SignupFullscreen'));
const SignupSmallFullscreen = React.lazy(() => import('./SignupSmallFullscreen'));
const SignupTablet = React.lazy(() => import('./SignupTablet'));
const SignupSmallTablet = React.lazy(() => import('./SignupSmallTablet'));
const SignupMobile = React.lazy(() => import('./SignupMobile'));
const { authToken, auth } = props
//Using the useWindowSize function to determine width of screen.
let [width] = useWindowSize();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//FULLSCREEN.
if(width >= 1425){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupFullscreen/>
</motion.div>
</React.Suspense>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SMALL FULLSCREEN.
else if( (width>1100)&&(width<=1425) ){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupSmallFullscreen/>
</motion.div>
</React.Suspense>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//FULL TABLET SCREEN.
else if( (width>650)&&(width<=1100) ){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupTablet/>
</motion.div>
</React.Suspense>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//HALF TABLET SCREEN.
else if( (width>425)&&(width<=650) ){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupSmallTablet/>
</motion.div>
</React.Suspense>
);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MOBILE SCREEN.
else if( width<=425 ){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupMobile/>
</motion.div>
</React.Suspense>
);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//DEFAULT IS FULLSCREEN
else {
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupFullscreen/>
</motion.div>
</React.Suspense>
);
}
}
const mapStateToProps = (state) => {
return {
authToken: state.auth.authToken,
authError: state.auth.authError,
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return {
}
}
//Used to determine width of the screen.
function useWindowSize() {
const [size, setSize] = useState([window.innerWidth]);
useEffect(() => {
const handleResize = () => {
setSize([window.innerWidth]);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
}
}, []);
return size;
}
export default connect(mapStateToProps, mapDispatchToProps)(SignupComponent)
向上、向下和横向寻找解决此问题的方法。
我的目标是将延迟加载分配给我的 React 网站中的几乎所有组件。但是,当这些组件进入和退出时,这些组件会利用 framer-motion 页面转换。页面转换和延迟加载的组合导致组件在作为路由单击时不再正确加载。
我从这个 post (https://github.com/reactjs/react-transition-group/issues/580) and tried to introduce the "react-lazy-with-preload" package (https://github.com/ianschmitz/react-lazy-with-preload) 中找到了灵感,但是我没能成功。
有人知道这个问题的解决方案吗?我肯定不是唯一一个尝试对使用具有成帧运动页面转换组件的 React 网站进行数据拆分的人。
App.js 代码如下:
import React, { Suspense } from 'react';
import { Switch, Route, useLocation } from 'react-router-dom';
import lazy from "react-lazy-with-preload";
import { AnimatePresence } from 'framer-motion';
////////////////////////////////////////////////
//PREPARE PAGES OF WEBSITE AS LAZY LOADED PAGES
import Navbar from './components/layout/Navbar/Navbar';
import Footer from './components/layout/Footer/Footer';
import Home from './components/layout/Homepage/Home';
const Dashboard = lazy(() => import('./components/dashboard/Dashboard'));
const Login = lazy(() => import('./components/authorization/login/LoginComponent'));
const SignUp = lazy(() => import('./components/authorization/signup/SignupComponent'));
const OurTeam = lazy(() => import( './components/layout/OurTeam/OurTeam'));
function App () {
let location = useLocation();
//Trying to preload the components which contain Page-Transitions
OurTeam.preload();
Login.preload();
SignUp.preload();
Dashboard.preload();
return (
<div className='page-container'>
<div className='content-wrap'>
<Navbar />
<AnimatePresence exitBeforeEnter> {/* Exit page transition occurs before next page loads. */}
<ScrollToTop/> {/* Causes the screen to scroll to the top after routing occurs. */}
<Switch location={location} key={location.pathname}> {/* Switch is used to make sure only 1 route is loaded up at a time. location and key are used for page transition animation.*/}
{/*Homepage will not be data-split and will always be loaded */}
<Route exact path='/' component={Home} />
<Suspense fallback='Loading...'>
<Route path='/OurTeam' component={OurTeam} />
</Suspense>
<Suspense fallback='Loading...'>
<Route path='/dashboard' component={Dashboard}/>
</Suspense>
<Suspense fallback='Loading...'>
<Route path='/login' component={Login} />
</Suspense>
<Suspense fallback='Loading...'>
<Route path='/signup' component={SignUp} />
</Suspense>
</Switch>
</AnimatePresence>
</div>
<Footer/>
</div>
);
//}
}
export default App;
未来读者的问题答案
在查阅了大量资源和其他教程后,我找到了解决我遇到的问题的方法。
简而言之,而不是在“App.js”中的路由处延迟加载组件(如上面问题中的代码所示)我决定在 Route 标记的每个组件内部延迟加载正在打电话。这是可行的,因为这些路由实际上会转到组件,这些组件将根据用户屏幕宽度加载非常特定的页面(请参阅下面的示例代码以获取我的注册页面):
SignupComponent.js 延迟加载前
import * as React from 'react';
import { useState, useEffect } from 'react';
import { connect } from 'react-redux'; //The library that holds react and redux together.
import { Redirect } from 'react-router-dom'; //Used to redirect logged out users to a different page.
import '../authorization.css'
//Page Transition imports
import { PageTransition } from '../../layout/PageTransition';
import {motion} from 'framer-motion';
import SignupFullscreen from './SignupFullscreen';
import SignupSmallFullscreen from './SignupSmallFullscreen';
import SignupTablet from './SignupTablet';
import SignupSmallTablet from './SignupSmallTablet';
import SignupMobile from './SignupMobile';
const SignupComponent = (props) => {
const { authToken, auth } = props
//Using the useWindowSize function to determine width of screen.
let [width] = useWindowSize();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//FULLSCREEN.
if(width >= 1425){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupFullscreen/>
</motion.div>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SMALL FULLSCREEN.
else if( (width>1100)&&(width<=1425) ){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupSmallFullscreen/>
</motion.div>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//FULL TABLET SCREEN.
else if( (width>650)&&(width<=1100) ){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupTablet/>
</motion.div>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//HALF TABLET SCREEN.
else if( (width>425)&&(width<=650) ){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupSmallTablet/>
</motion.div>
);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MOBILE SCREEN.
else if( width<=425 ){
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupMobile/>
</motion.div>
);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//DEFAULT IS FULLSCREEN
else {
return(
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupFullscreen/>
</motion.div>
);
}
}
const mapStateToProps = (state) => {
return {
authToken: state.auth.authToken,
authError: state.auth.authError,
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return {
}
}
//Used to determine width of the screen.
function useWindowSize() {
const [size, setSize] = useState([window.innerWidth]);
useEffect(() => {
const handleResize = () => {
setSize([window.innerWidth]);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
}
}, []);
return size;
}
export default connect(mapStateToProps, mapDispatchToProps)(SignupComponent)
要引入延迟加载,只需将这些组件中的每一个包装在
SignupComponent.js 添加延迟加载后
import * as React from 'react';
import { useState, useEffect } from 'react';
import { connect } from 'react-redux'; //The library that holds react and redux together.
import { Redirect } from 'react-router-dom'; //Used to redirect logged out users to a different page.
import '../authorization.css'
//Page Transition imports
import { PageTransition } from '../../layout/PageTransition';
import {motion} from 'framer-motion';
const SignupComponent = (props) => {
const SignupFullscreen = React.lazy(() => import('./SignupFullscreen'));
const SignupSmallFullscreen = React.lazy(() => import('./SignupSmallFullscreen'));
const SignupTablet = React.lazy(() => import('./SignupTablet'));
const SignupSmallTablet = React.lazy(() => import('./SignupSmallTablet'));
const SignupMobile = React.lazy(() => import('./SignupMobile'));
const { authToken, auth } = props
//Using the useWindowSize function to determine width of screen.
let [width] = useWindowSize();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//FULLSCREEN.
if(width >= 1425){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupFullscreen/>
</motion.div>
</React.Suspense>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SMALL FULLSCREEN.
else if( (width>1100)&&(width<=1425) ){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupSmallFullscreen/>
</motion.div>
</React.Suspense>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//FULL TABLET SCREEN.
else if( (width>650)&&(width<=1100) ){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupTablet/>
</motion.div>
</React.Suspense>
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//HALF TABLET SCREEN.
else if( (width>425)&&(width<=650) ){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupSmallTablet/>
</motion.div>
</React.Suspense>
);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MOBILE SCREEN.
else if( width<=425 ){
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupMobile/>
</motion.div>
</React.Suspense>
);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//DEFAULT IS FULLSCREEN
else {
return(
<React.Suspense fallback={<p>Loading list...</p>}>
<motion.div exit='exit' variants={PageTransition} initial='hidden' animate='show'>
<SignupFullscreen/>
</motion.div>
</React.Suspense>
);
}
}
const mapStateToProps = (state) => {
return {
authToken: state.auth.authToken,
authError: state.auth.authError,
auth: state.firebase.auth
}
}
const mapDispatchToProps = (dispatch) => {
return {
}
}
//Used to determine width of the screen.
function useWindowSize() {
const [size, setSize] = useState([window.innerWidth]);
useEffect(() => {
const handleResize = () => {
setSize([window.innerWidth]);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
}
}, []);
return size;
}
export default connect(mapStateToProps, mapDispatchToProps)(SignupComponent)