javascript - 使用 useEffect 加载脚本

我正在使用 sdk,根据文档我必须加载脚本:

 <body>
 <script>
    my sdk code
    my sdk code
    my sdk code
  </script>
  ..
  ..
  </body>

如何查看标签内部 我有 sdk 代码。我正在使用 reactJs,我想在 useEffect Hook 中加载这个脚本。
问题:如何不在body标签中而是在useEffect hook中运行sdk的脚本?

最佳答案

您需要在 React 组件内动态添加脚本标签。执行此操作的最佳方法是使用上下文 API。它将提供一个加载脚本和启动 FB SDK 的单一点,并且可以让每个 child 知道何时加载脚本并且 SDK 可以使用。

FbSdkScript.js

import React, { 
  createContext, 
  useContext, 
  useState, 
  useEffect 
} from 'react'

// Context.
export const FbSdkScriptContext = createContext()

// Create a custom hook to use the context.
export const useFbSdkScriptContext = () => useContext(FbSdkScriptContext)

// Provider of context.
const FbSdkScriptProvider = ({
  appId,
  autoLogAppEvents = true,
  xfbml = true,
  version = 'v8.0',
  children 
}) => {
  const [hasLoaded, setHasLoaded] = useState(false)
  const [isReady, setIsReady] = useState(false)

  /**
   * Extra security measure to check if the script has
   * already been included in the DOM
   */
  const scriptAlreadyExists = () => 
    document.querySelector('script#fb-sdk') !== null

  /**
   * Append the script to the document.
   * Whenever the script has been loaded it will
   * set the isLoaded state to true.
   */
  const appendSdkScript = () => {
    const script = document.createElement('script')
    script.id = 'fb-sdk'
    script.src = 'https://connect.facebook.net/en_US/sdk.js'
    script.async = true
    script.defer = true
    script.crossOrigin = 'anonymous'
    script.onload = () => setHasLoaded(true)
    document.body.append(script)
  };
  
  /**
   * Runs first time when component is mounted
   * and adds the script to the document.
   */
  useEffect(() => {
    if (!scriptAlreadyExists()) {
      appendSdkScript()
    }
  }, []);

  /**
   * Whenever the script has loaded initialize the
   * FB SDK with the init method. This will then set
   * the isReady state to true and passes that
   * through the context to the consumers.
   */
  useEffect(() => {
    if (hasLoaded === true) {
      FB.init({
        appId,
        autoLogAppEvents,
        xfbml,
        version 
      })
      setIsReady(true)
    }
  }, [hasLoaded])

  return (
    <FbSdkScriptContext.Provider value={{ isReady, hasLoaded }}>
      {children}
    </FbSdkScriptContext.Provider>
  )
}

export default FbSdkScriptProvider

共享组件本身现在无需担心。它只需要知道脚本什么时候加载,FB SDK 已经初始化。它将通过 Context API 的 isReady 状态获取该信号。

FbShareDialog.js

import React, { useEffect } from 'react'
import { useFbSdkScriptContext } from './FbSdkScript'

/**
 * This is the button that will trigger the dialog.
 * It uses the context created in the previous snippet to
 * know when the script has loaded and the API is ready
 * to use. 
 */
const FbShareDialog = ({ method = 'share', href }) => {
  const { isReady } = useFbSdkScriptContext()

  /**
   * Open share dialog when the button is clicked.
   * This will only be available when the isReady
   * state is true.
   */
  const handleClick = () => {
    FB.ui({
      method,
      href,
    }, response => {
      console.log(response)
    })
  }

  /**
   * If FB SDK is not yet ready, don't render the button.
   */
  if (!isReady) {
    return null
  }

  /**
   * Otherwise do render the button and set an onClick
   * event listener which triggers the dialog.
   */
  return (
    <button onClick={handleClick}>Share me</button>
  )
}

export default FbShareDialog

所有这些都集中在一个组件中,其中上下文提供程序是共享对话框按钮的父级。您只需传递 appId 即可让 FbSdkScriptProvider 组件正常工作。并将 href 添加到按钮以告诉 FB.ui 引用什么 href。

App.js

import React from 'react'

import FbSdkScriptProvider from './FbSdkScript'
import FbShareDialog from './FbShareDialog'

const App = () => (
  <FbSdkScriptProvider appId={'your-app-id'}>
    <FbShareDialog href={'https://developers.facebook.com/docs/'} />
  <FbSdkScriptProvider/>
)

https://stackoverflow.com/questions/64297146/

相关文章:

vue.js - 如何制作可点击的带有悬停效果的q卡?

reactjs - 不能在 JSX 属性中使用 bool 值

python - 在Python中随机生成二维列表

python - 为什么 python 的 "gc.collect()"没有按预期工作?

python-3.x - Python Pandas : groupby one column, 只

python-3.x - Pygame - 不存在 "Setup"文件,正在运行 "buildcon

java - 如何使用 void set 方法在静态常量帮助程序类中创建对象?

javascript - 在 React Native 中安排本地通知不起作用

react-native - React native 每次打开页面时如何执行函数

haskell - 在 Haskell 的 do 上下文中应用构造函数