问题
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="© <a href="http://osm.org/copyright">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