Last active
March 1, 2023 16:50
-
-
Save mike-at-redspace/e8076033ece3392b824153fa311ca3b7 to your computer and use it in GitHub Desktop.
Import on Interaction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from 'react' | |
import useScript from './useScript' | |
import useFirstInteraction from './useFirstInteraction' | |
const App = () => { | |
const [{ loaded, error }, triggerScript] = useScript('<url-to-script>') | |
useFirstInteraction(() => { | |
triggerScript() | |
}, 5) | |
return ( | |
<div> | |
{!loaded && !error && <p>Script is not loaded yet</p>} | |
{loaded && !error && <p>Script is loaded</p>} | |
{error && <p>An error occurred while loading the script</p>} | |
</div> | |
) | |
} | |
export default App |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect } from 'react' | |
const useFirstInteraction = (callback, delay) => { | |
const controller = new AbortController() | |
const { signal } = controller | |
useEffect(() => { | |
let timeoutId = null | |
const handleInteraction = () => { | |
callback() | |
controller.abort() | |
} | |
const handleDelay = () => { | |
timeoutId = setTimeout(() => { | |
handleInteraction() | |
}, delay * 1000) | |
} | |
document.addEventListener('scroll', handleInteraction, { signal }) | |
document.addEventListener('click', handleInteraction, { signal }) | |
document.addEventListener('keydown', handleInteraction, { signal }) | |
document.addEventListener('touchstart', handleInteraction, { signal }) | |
handleDelay() | |
return () => { | |
clearTimeout(timeoutId) | |
controller.abort() | |
} | |
}, [callback, delay]) | |
} | |
export default useFirstInteraction |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from 'react' | |
const useScript = url => { | |
const [state, setState] = useState({ | |
loaded: false, | |
error: false | |
}) | |
const onLoad = () => { | |
setState({ | |
loaded: true, | |
error: false | |
}) | |
} | |
const onError = () => { | |
setState({ | |
loaded: false, | |
error: true | |
}) | |
} | |
const addScript = url => { | |
const script = document.createElement('script') | |
script.src = url | |
script.async = true | |
script.addEventListener('load', onLoad) | |
script.addEventListener('error', onError) | |
document.body.appendChild(script) | |
return () => { | |
script.removeEventListener('load', onLoad) | |
script.removeEventListener('error', onError) | |
document.body.removeChild(script) | |
} | |
} | |
const triggerScript = () => { | |
setState({ | |
loaded: false, | |
error: false | |
}) | |
addScript(url) | |
} | |
return [state, triggerScript] | |
} | |
export default useScript |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { render, cleanup, fireEvent } from '@testing-library/react' | |
import useScript from './useScript' | |
jest.mock('./script.js', () => { | |
return jest.fn() | |
}) | |
afterEach(cleanup) | |
describe('useScript', () => { | |
it('should load the script and update the state', () => { | |
const url = './script.js' | |
const TestComponent = () => { | |
const [state, triggerScript] = useScript(url) | |
return ( | |
<div> | |
<button data-testid='load-button' onClick={triggerScript}> | |
Load Script | |
</button> | |
<div data-testid='loaded-state'> | |
{state.loaded ? 'Loaded' : 'Not Loaded'} | |
</div> | |
</div> | |
) | |
} | |
const { getByTestId } = render(<TestComponent />) | |
fireEvent.click(getByTestId('load-button')) | |
expect(getByTestId('loaded-state').textContent).toBe('Loaded') | |
}) | |
it('should handle script load error and update the state', () => { | |
const url = './bad-script.js' | |
const TestComponent = () => { | |
const [state, triggerScript] = useScript(url) | |
return ( | |
<div> | |
<button data-testid='load-button' onClick={triggerScript}> | |
Load Script | |
</button> | |
<div data-testid='error-state'> | |
{state.error ? 'Error' : 'No Error'} | |
</div> | |
</div> | |
) | |
} | |
const { getByTestId } = render(<TestComponent />) | |
fireEvent.click(getByTestId('load-button')) | |
expect(getByTestId('error-state').textContent).toBe('Error') | |
}) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment