Skip to content

Commit

Permalink
ON-41217 # Added useLoadDataEffect hook
Browse files Browse the repository at this point in the history
  • Loading branch information
mymattcarroll committed Jun 13, 2024
1 parent be896a0 commit 909159c
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `useLoadDataEffect()` hook

### Fixed

- accessibility attributes for checkbox and radio labels
Expand Down
58 changes: 58 additions & 0 deletions src/hooks/useLoadDataEffect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react'

/**
* This function is a react hook for loading data and reloading it with a way of
* aborting the request. Useful when using reducers to load data asynchronously
* and store the state outside of this react hook.
*
* ## Example
*
* ```js
* import { useLoadDataEffect } from '@oneblink/apps-react'
*
* const fetchData = async (abortSignal) => {
* const response = await fetch(
* `https://some-website.com/api?data=data`,
* {
* signal: abortSignal,
* },
* )
*
* const data = await response.json()
* // store data in a data layer for later use
* }
*
* export default function MyComponent() {
* const handleRefresh = useLoadDataEffect(fetchData)
*
* return <button onClick={handleRefresh}>Refresh</button>
* }
* ```
*
* @param onLoad The function that fetches your data and stores it for later
* use.
* @returns A function to reload the data
* @group Hooks
*/
export default function useLoadDataEffect(
onLoad: (abortSignal: AbortSignal) => void,
): () => void {
// We use a number to trigger the refresh function so that
// we can pass an abort controller using a useEffect and
// have it aborted if the refresh function is triggered again.
const [loadCount, setLoadCount] = React.useState(0)

const handleReload = React.useCallback(() => {
setLoadCount((currentLoadCount) => currentLoadCount + 1)
}, [])

React.useEffect(() => {
const abortController = new AbortController()
onLoad(abortController.signal)
return () => {
abortController.abort()
}
}, [loadCount, onLoad])

return handleReload
}
18 changes: 2 additions & 16 deletions src/hooks/useLoadDataState.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react'
import useIsMounted from './useIsMounted'
import useLoadDataEffect from './useLoadDataEffect'

export type LoadDataState<T> =
| {
Expand Down Expand Up @@ -114,22 +115,7 @@ export default function useLoadDataState<T>(
[],
)

// We use a number to trigger the refresh function so that
// we can pass an abort controller using a useEffect and
// have it aborted if the refresh function is triggered again.
const [loadCount, setLoadCount] = React.useState(0)

const handleRefresh = React.useCallback(() => {
setLoadCount((currentLoadCount) => currentLoadCount + 1)
}, [])

React.useEffect(() => {
const abortController = new AbortController()
handleLoad(abortController.signal)
return () => {
abortController.abort()
}
}, [handleLoad, loadCount])
const handleRefresh = useLoadDataEffect(handleLoad)

return [state, handleRefresh, setResult]
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export {
LoadDataState,
} from './hooks/useLoadDataState'
export { default as useLoadResourcesState } from './hooks/useLoadResourcesState'
export { default as useLoadDataEffect } from './hooks/useLoadDataEffect'
export { default as useFormSubmissionState } from './hooks/useFormSubmissionState'
export { default as useFormSubmissionAutoSaveState } from './hooks/useFormSubmissionAutoSaveState'
export { default as useGoogleJsApiLoader } from './hooks/useGoogleJsApiLoader'
Expand Down

0 comments on commit 909159c

Please sign in to comment.