Skip to content

Instantly share code, notes, and snippets.

@mbrowne
Last active September 16, 2025 20:09
Show Gist options
  • Save mbrowne/0ea7068e8f00ffdd8b06f5fba945707f to your computer and use it in GitHub Desktop.
Save mbrowne/0ea7068e8f00ffdd8b06f5fba945707f to your computer and use it in GitHub Desktop.
React-router / Remix helper functions to detect when data has successfully loaded from a loader or fetcher
import React from 'react'
import { useNavigation, type FetcherWithComponents } from 'react-router'
/**
* Calls the provided callback function whenever react-router loader data is successfully
* loaded. This is intended to be used in conjunction with `useLoaderData()`.
*
* Example:
const data = useLoaderData<LoaderData>()
useOnLoaderSuccess(() => {
// do something with `data`
})
*/
export function useOnLoaderSuccess(onSuccess: () => void) {
const { state } = useNavigation()
const idle = state === 'idle'
const prevIdle = React.useRef(false)
React.useEffect(() => {
if (idle && !prevIdle.current) {
onSuccess()
}
prevIdle.current = idle
}, [onSuccess, idle])
}
/**
* Calls the provided callback function whenever data from the fetcher is successfully
* loaded. This is intended to be used in conjunction with `useFetcher()`.
*
* Example:
const fetcher = useFetcher<FetcherData>()
useOnFetcherSuccess(fetcher, () => {
// do something with `fetcher.data`
})
*/
export function useOnFetcherSuccess<TData>(
fetcher: FetcherWithComponents<TData>,
onSuccess: () => void
) {
const submitting = fetcher.state === 'submitting'
const prevSubmitting = React.useRef(false)
React.useEffect(() => {
if (!submitting && prevSubmitting.current) {
onSuccess()
}
prevSubmitting.current = submitting
}, [onSuccess, submitting])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment