Hookpedia
Ctrl + K
Repositório no GitHub

useScript

Compartilhar no Twitter

18 de abril de 2022

Esse hook faz com que carregar scripts externos dinamicamente e saber quando são carregados seja feio de forma super fácil. É útil quando você precisa interagir com bibliotecas de terceiros (como Stripe, Google Analytics e etc.) e você prefere carregar o script quando é preciso ao invés de declarar no head do documento para cada requisição.

import { useState, useEffect } from "react";

// Forma de uso
function App() {
  const status = useScript(
    "https://pm28k14qlj.codesandbox.io/test-external-script.js"
  );
  return (
    <div>
      <div>
        Script status: <b>{status}</b>
      </dv>
      {status === "ready" && (
        <div>
          Script function call response: <b>{TEST_SCRIPT.start()}</b>
        </div>
      )}
    </div>
  );
}
// Hook
function useScript(src) {
  // Observa os status do script ("idle", "loading", "ready", "error")
  const [status, setStatus] = useState(src ? "loading" : "idle");
  
  useEffect(
    () => {
      // Permite valores 'falsy' se esperando por outros dados
      // necessários para construir a URL do script passado para esse hook.
      if (!src) {
        setStatus("idle");
        return;
      }

      // Fazendo fetch do elemento do script pela url
      // Pode ter sido adicionado por outra instância desse hook.
      let script = document.querySelector(`script[src="${src}"]`);
      
      if (!script) {
        // Criando script
        script = document.createElement("script");
        script.src = src;
        script.async = true;
        script.setAttribute("data-status", "loading");
        // Adicionar script para o  corpo do documento
        document.body.appendChild(script);

        // Guarda o status no atributo do script
        // Isso pode ser lido por outras instâncias desse hook.
        const setAttributeFromEvent = (event) => {
          script.setAttribute(
            "data-status",
            event.type === "load" ? "ready" : "error"
          );
        };

        script.addEventListener("load", setAttributeFromEvent);
        script.addEventListener("error", setAttributeFromEvent);
      } else {
        // Pega status de scripts existentes do atributo e define o estado.
        setStatus(script.getAttribute("data-status"));
      }
      
      // Handler para atualizar status no estado
      // Nota: Mesmo que o script já exista, precisamos adicionar
      // event handlers para atualizar o state dessa instância do hook.
      const setStateFromEvent = (event) => {
        setStatus(event.type === "load" ? "ready" : "error");
      };

      // Adicionando event listeners
      script.addEventListener("load", setStateFromEvent);
      script.addEventListener("error", setStateFromEvent);
      
      // Removendo event listeners ao limpar componente
      return () => {
        if (script) {
          script.removeEventListener("load", setStateFromEvent);
          script.removeEventListener("error", setStateFromEvent);
        }
      };
    },
    [src] // Rodar novamente apenas quando o src mudar
  );
  return status;
}

Criado por @guilherssousa, mantido por 1 pessoas 💗