How to make a script working the first time for a special component with gatsby?

天涯浪子 提交于 2020-07-22 11:12:13

问题


I am working on a static website project using Gatsby. I have several markdown pages, and only one is using a script through a cdn call. Instead of calling my script wherever i am on the website, I only to want to call and use my script when I need to update my <head>. That's why I started to use logical inside my Helmet component.

Actual version (calling on every pages):

return(
    <Layout>
    <Seo />
    <Helmet>
      <script src="myScriptForOnePage.js" />
    </Helmet>
    ....
    </Layout>
);

Excepted version:

return(
    <Layout>
    <Seo />
    { ifIHaveToRenderMyPage ? (
     <Helmet>
       <script src="myScriptForOnePage.js" />
     </Helmet>
    ):null}
    ....
    </Layout>
);

This works fine. My script is only loaded when I need it. However, It is not executed the first time when I load my special page... I need to go twice on my page to see my loaded script working.

This is an illustration of the issue. For example, in this project, I want to add a leaflet map. So, myScriptForOnePage.js equals to https://unpkg.com/leaflet@1.6.0/dist/leaflet.js (plus css file).

When I first load the page:

As you might see, L is not defined. My script is not executed even if it is present in the network statement. When I go back on the menu, and click again on leaflet post (without reloading):

The map is ready to be displayed.

Am I missing something in the life component? How can I fix this?


回答1:


Due to the asynchronously of Gatsby and your issue, you need to use an state to rerender the DOM and add a new component (<Helmet>) when your ifIHaveToRenderMyPage is set. Try:

import React, { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet';
const yourComponent = () => {
  const [myScript, setMyScript] = useState([]);

  useEffect(() => {
    let myScriptForOnePage= <Helmet>
      <script src="myScriptForOnePage.js" />
    </Helmet>;

    setMyScript(myScriptForOnePage);

  },[]);
return(
    <Layout>
    <Seo />
    {ifIHaveToRenderMyPage && myScript}
    ....
    </Layout>
);

So, basically I use a useState hook initially set as an empty array (must be an empty array to be filled with a component) and I've created an effect using useEffect hook that triggers when the component and DOM tree is generated (you can use ifIHaveToRenderMyPage as a dependency if you want by [ifIHaveToRenderMyPage]).

In addition, I've changed the ternary condition because you don't need to return a null value, just check if ifIHaveToRenderMyPage is true using && comparator, it's cleaner and efficient.

In my local machine with a build command and first rendering:

With the new updates, have you tried importing L from leaflet? As the official documentation shows:

import React from 'react'
import { render } from 'react-dom'
import { Map, Marker, Popup, TileLayer } from 'react-leaflet'

const position = [51.505, -0.09]
const map = (
  <Map center={position} zoom={13}>
    <TileLayer
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      attribution="&copy; <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"
    />
    <Marker position={position}>
      <Popup>A pretty CSS3 popup.<br />Easily customizable.</Popup>
    </Marker>
  </Map>
)

render(map, document.getElementById('map-container'))


来源:https://stackoverflow.com/questions/62635153/how-to-make-a-script-working-the-first-time-for-a-special-component-with-gatsby

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