// @flow import * as React from 'react' import loadScript, { getState } from "./loadScript.js" export type State = {| loading: boolean, loaded: boolean, error: ?Error, promise: ?Promise, |} export type Props = { src: string, onLoad?: ?() => any, onError?: ?(error: Error) => any, children?: ?(state: State) => ?React.Node, act?: ?(action: () => void) => void, ... } export type InnerProps = { ...$Exact, scriptsRegistry?: ?ScriptsRegistry, ... } export function useScript(props: Props): State { const isMounted = React.useRef(true) React.useEffect( () => () => { isMounted.current = false }, [] ) const scriptsRegistry = React.useContext(ScriptsRegistryContext) const [, rerender] = React.useReducer((count = 0) => count + 1) const propsRef = React.useRef(props) propsRef.current = props const act = React.useCallback((fn: () => void) => { if (!isMounted.current) return const { act } = propsRef.current if (act) act(fn) else fn() }, []) const promise = React.useMemo( () => loadScript({ ...props, scriptsRegistry }), [props.src, scriptsRegistry] ) React.useEffect(() => { if (!isMounted.current) return promise.then( () => act(() => { propsRef.current.onLoad?.() rerender() }), (error: Error) => act(() => { propsRef.current.onError?.(error) rerender() }) ) }, [promise]) return getState({ ...props, scriptsRegistry }) } export class ScriptsRegistry { scripts: Array<{ src: string, ... }> = [] results: { [src: string]: { error: ?Error } } = {} promises: { [src: string]: Promise } = {} scriptTags(options?: {| nonce?: string |}): React.Node { return this.scripts.map((props) => (