问题
I copied a simple full page preloader via jQuery on my Gatsby app. The preloader works however instead of disappearing after 4 seconds its loading forever on production but on local it works just fine.
Here's my Preloader
component:
import React from 'react'
const Preloader = () => {
return (
<div id="loader-wrapper">
<div id="loader"></div>
<div className="loader-section section-left"></div>
<div className="loader-section section-right"></div>
</div>
)
}
export default Preloader
And then on my script.js
(which was included inside <Helmet>
):
jQuery.noConflict();
(function ($) {
var windows = $(window);
/* preloader */
setTimeout(function(){
$('body').addClass('loaded');
$('h1').css('color','#222222');
}, 400);
})(jQuery);
I added this preloader on my index.js
:
return (
<>
<Preloader />
<SEO />
<div className="main-container">
<Layout>
<Header />
<Testimonials title="Testimonials" />
<Blogs title="Latest Blogs" blogs={blogs} showAllBlogLinks/>
<Map />
</Layout>
</div>
</>
)
}
Any idea what's causing this and how to fix it?
回答1:
I've faced a similar issue a few months ago and the fix depends strictly on the implementation and your code. Basically, what is happening is that React's doesn't understand that he needs to rehydrate some components because pointing to some global objects as window
or document
of the DOM, outside the React's ecosystem (without using states) may block that rehydration, in your cause, because of jQuery.
All the possible solutions that bypass this issue will be patches (like trying to add the cache). The ideal solution would avoid using jQuery, which points directly to the DOM, with React, which manipulates the virtual DOM (vDOM). This line is breaking your rehydration:
var windows = $(window);
The most weird thing here is that on local upon running npx gatsby develop it shows all of my data. Really weird
It's not, again: gatsby develop
occurs in the browser, where there's a window
object, on the other hand, gatsby build
occurs in the server (Node) where there's no window or other global objects because they are not even created.
In addition, you can easily transform this snippet:
setTimeout(function() {
document.querySelector("body").classList.add("loaded");
document.querySelector("h1").style = "color: #222222";
}, 400)
Into a React-based one, using hooks:
const [loader, setLoader]=useState(true);
useEffect(()=>{
setTimeout(()=> {
setLoader(false)
}, 400)
}, [])
return (
<>
<SEO />
{loader
? <Preloader />
: <div className="main-container">
<Layout>
<Header />
<Testimonials title="Testimonials" />
<Blogs title="Latest Blogs" blogs={blogs} showAllBlogLinks/>
<Map />
</Layout>
</div>
}
</>
)
}
As a resume. You are setting initially the loader as true (useState(true)
), and once the DOM tree is loaded (useEffect
with empty deps
, []
), you trigger your setTimeout
function, which toggles the value of loader
from true
to false
. This will choose what component render using a ternary condition at: loader ? <Preloader/> : <OtherComponents />
If you need to use the window
size object, you can use a React-based approach, like the one provided here.
Is there a way to improve this and make the preloader loads everytime you visit another page?
Yes, the idea is to move that loader logic to the <Layout>
component, since all the pages will share it:
const Layout = ({ children }) => {
const [loader, setLoader]=useState(true);
useEffect(()=>{
setTimeout(()=> {
setLoader(false)
}, 400)
}, [])
return <section className={`site__wrapper`}>
<Header />
<main>{loader ? <Preloader/> : children}</main>
</section>;
};
I don't know how your <Layout>
component looks like but the idea is to add something similar. Since your <Layout>
is shared across your site, each re-rendering of the component will rehydrate this component, forcing the initial loader state as true
and changing it to false
at 400ms, rendering the children
, which is everything wrapped inside the <Layout>
component on other pages.
回答2:
Have you tried adding your code inside gatsby-browser.js
instead something like this?
export const onInitialClientRender = () => {
setTimeout(function() {
document.querySelector("body").classList.add("loaded");
document.querySelector("h1").style = "color: #222222";
}, 400)
}
来源:https://stackoverflow.com/questions/65802810/gatsby-js-preloader-is-loading-forever