-
-
Save addisonschultz/1811e75b498311211a7f6b8634fb27cd to your computer and use it in GitHub Desktop.
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 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?
You can totally use css inside of Framer X! The easiest and most straight forward way is to include the css file in the code
folder of your Framer X Project. If you're loading it from a link, maybe the above solution is the best!
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
export function Component(props) {
return (
<div className={props.className}></div>
)
}
addPropertyControls(Component, {
className: {type: ControlType.String, title: "Class Name"}
})
thank you :)
What's the best way to execute a function after the script is loaded?
@AndrewTraub I would suggest using it in the useEffect
from the example above. It returns a boolean if it's loaded, and if so, you can then do what you'd like from there.
what if the script exists as a project file and not a url? how would you modify the hook?
@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 constants.tsx
to see the actual util
Here is an example of using this inside of a Framer Component: