import * as React from "react" | |
import { useState, useEffect } from "react" | |
// Hook | |
let cachedScripts = [] | |
export function useScript(src) { | |
// Keeping track of script loaded and error state | |
const [state, setState] = useState({ | |
loaded: false, | |
error: false, | |
}) | |
useEffect(() => { | |
// If cachedScripts array already includes src that means another instance ... | |
// ... of this hook already loaded this script, so no need to load again. | |
if (cachedScripts.includes(src)) { | |
setState({ | |
loaded: true, | |
error: false, | |
}) | |
} else { | |
cachedScripts.push(src) | |
// Create script | |
let script = document.createElement("script") | |
script.src = src | |
script.async = true | |
// Script event listener callbacks for load and error | |
const onScriptLoad = () => { | |
setState({ | |
loaded: true, | |
error: false, | |
}) | |
} | |
const onScriptError = () => { | |
// Remove from cachedScripts we can try loading again | |
const index = cachedScripts.indexOf(src) | |
if (index >= 0) cachedScripts.splice(index, 1) | |
script.remove() | |
setState({ | |
loaded: true, | |
error: true, | |
}) | |
} | |
script.addEventListener("load", onScriptLoad) | |
script.addEventListener("error", onScriptError) | |
// Add script to document body | |
document.body.appendChild(script) | |
// Remove event listeners on cleanup | |
return () => { | |
script.removeEventListener("load", onScriptLoad) | |
script.removeEventListener("error", onScriptError) | |
} | |
} | |
}, [src]) // Only re-run effect if script src changes | |
return [state.loaded, state.error] | |
} |
This comment has been minimized.
This comment has been minimized.
This rocks! Question - I've built out my design system with the external stylesheet and CSS variables. Any tips or tricks on getting that available inside framer x? |
This comment has been minimized.
This comment has been minimized.
You can totally use css inside of Framer X! The easiest and most straight forward way is to include the css file in the Make sure you include the className in the component as well. A cool way you could have a dynamic component that you can change would be something like
|
This comment has been minimized.
This comment has been minimized.
thank you :) |
This comment has been minimized.
This comment has been minimized.
What's the best way to execute a function after the script is loaded? |
This comment has been minimized.
This comment has been minimized.
@AndrewTraub I would suggest using it in the |
This comment has been minimized.
This comment has been minimized.
what if the script exists as a project file and not a url? how would you modify the hook? |
This comment has been minimized.
This comment has been minimized.
@ridhwaans I have a Framer Example that lets you choose either a URL or a local file using a property control in the component itself :) You can see how it's set up here: https://github.com/framer/framer-bridge-stencil-kit/tree/master/code/utils You can look into |
This comment has been minimized.
Here is an example of using this inside of a Framer Component: