Gatsby JS:预加载器永远加载

Gatsby JS: Preloader is loading forever

我通过 jQuery 在我的 Gatsby 应用程序上复制了一个简单的整页预加载器。然而,预加载器可以工作,而不是在 4 秒后消失,它在生产环境中永远加载,但在本地它工作得很好。

这是我的 Preloader 组件:

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

然后在我的 script.js(包含在 <Helmet> 中):

jQuery.noConflict();
    
(function ($) {

    var windows = $(window);

    /* preloader */
    setTimeout(function(){
        $('body').addClass('loaded');
        $('h1').css('color','#222222');
    }, 400);
    
   
})(jQuery);

我在 index.js:

上添加了这个预加载器
return (
     <>
    <Preloader />
    <SEO />
    <div className="main-container">
      <Layout>
      <Header />
      <Testimonials title="Testimonials" />
      <Blogs title="Latest Blogs" blogs={blogs} showAllBlogLinks/>
      <Map />
      </Layout>
    </div> 
    </>
  )
}

知道是什么原因造成的以及如何解决吗?

您是否尝试过将您的代码添加到 gatsby-browser.js 而不是像这样的东西?

export const onInitialClientRender = () => {
    setTimeout(function() {
        document.querySelector("body").classList.add("loaded");
        document.querySelector("h1").style = "color: #222222";
    }, 400)
}

几个月前我遇到过类似的问题,修复完全取决于实现和您的代码。基本上,正在发生的事情是 React 不明白他需要重新水合某些组件,因为在 React 的生态系统之外将某些全局对象指向 DOM 的 windowdocument(不使用状态)可能会阻止补液,因为 jQuery.

绕过这个问题的所有可能解决方案都是补丁(比如尝试添加缓存)。理想的解决方案是避免使用直接指向 DOM 的 jQuery,以及操纵虚拟 DOM (vDOM) 的 React。这条线正在破坏你的补液:

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

又不是:gatsby develop 出现在浏览器中,其中有一个 window 对象,另一方面,gatsby build 出现在没有对象的服务器(节点)中window or other global objects 因为它们甚至还没有被创建。

此外,您可以轻松转换此代码段:

setTimeout(function() {
    document.querySelector("body").classList.add("loaded");
    document.querySelector("h1").style = "color: #222222";
}, 400)

进入基于 React 的,使用钩子:

   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> 
     }
    </>
  )
}

作为简历。您最初将加载程序设置为 true (useState(true)),并且一旦 DOM 树被加载(useEffect with empty deps, []),您触发您的 setTimeout 函数,它将 loader 的值从 true 切换为 false。这将选择使用三元条件渲染的组件:loader ? <Preloader/> : <OtherComponents />

如果您需要使用 window 大小的对象,您可以使用基于 React 的方法,例如提供的方法 here

Is there a way to improve this and make the preloader loads everytime you visit another page?

是的,我们的想法是将该加载程序逻辑移动到 <Layout> 组件,因为所有页面都将共享它:

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

我不知道你的 <Layout> 组件是什么样子,但我的想法是添加类似的东西。由于您的 <Layout> 在您的网站上共享,每次重新呈现组件都会重新水化该组件,强制初始加载器状态为 true 并在 400 毫秒时将其更改为 false,呈现children,这是包裹在其他页面上的 <Layout> 组件中的所有内容。