如何使用gatsby使脚本首次使用特殊组件? [英] How to make a script working the first time for a special component with gatsby?

查看:77
本文介绍了如何使用gatsby使脚本首次使用特殊组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Gatsby从事静态网站项目.我有几个markdown页面,只有一个通过cdn调用使用脚本.我不需要在网站上的任何地方调用脚本,而只想在需要更新<head>时调用和使用脚本.这就是为什么我开始在头盔组件中使用逻辑的原因.

实际版本(每页调用一次):

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

例外版本:

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

这很好.我的脚本仅在需要时加载. 但是,在加载特殊页面时不会第一次执行...我需要在页面上浏览两次以查看加载的脚本是否正常工作.

这是该问题的例证.例如,在这个项目中,我想添加一个传单地图.因此,myScriptForOnePage.js等于https://unpkg.com/leaflet@1.6.0/dist/leaflet.js(加上CSS文件).

当我第一次加载页面时:

如您所见,L is not defined.即使脚本在network语句中也不会执行.当我返回菜单时,再次单击传单(无需重新加载):

可以随时显示地图.

我在生活中缺少某些东西吗?我该如何解决?

解决方案

由于Gatsby和您的问题是异步的,因此当出现以下情况时,您需要使用state重新呈现DOM并添加新的组件(<Helmet>)您的ifIHaveToRenderMyPage已设置.试试:

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

因此,基本上,我使用一个useState钩子,该钩子最初设置为一个空数组(必须是一个要填充组件的空数组),并且我已经使用useEffect钩子创建了一个效果,该效果会在组件和组件生成DOM树(如果需要,可以使用ifIHaveToRenderMyPage作为依赖项).

此外,我已经更改了三元条件,因为您不需要返回null值,只需使用&&比较器检查ifIHaveToRenderMyPage是否为true,它就会更干净,更高效.

在我的本地计算机中,使用build命令并首先进行渲染:

有了新的更新,您是否尝试过从传单中导入L?如官方文档所示:

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'))

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?

解决方案

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'))

这篇关于如何使用gatsby使脚本首次使用特殊组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆