Gatsby JS: Preloader is loading forever

女生的网名这么多〃 提交于 2021-02-19 08:43:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!