MCPcopy Create free account
hub / github.com/ckeditor/ckeditor5-react / useAsyncCallback

Function useAsyncCallback

src/hooks/useAsyncCallback.ts:36–98  ·  view source on GitHub ↗
(
	callback: ( ...args: A ) => Promise<R>
)

Source from the content-addressed store, hash-verified

34 * ```
35 */
36export const useAsyncCallback = <A extends Array<unknown>, R>(
37 callback: ( ...args: A ) => Promise<R>
38): AsyncCallbackHookResult<A, R> => {
39 // The state of the asynchronous callback.
40 const [ asyncState, setAsyncState ] = useState<AsyncCallbackState<R>>( {
41 status: 'idle'
42 } );
43
44 // A reference to the mounted state of the component.
45 const unmountedRef = useIsUnmountedRef();
46
47 // A reference to the previous execution UUID. It is used to prevent race conditions between multiple executions
48 // of the asynchronous function. If the UUID of the current execution is different than the UUID of the previous
49 // execution, the state is not updated.
50 const prevExecutionUIDRef = useRef<string | null>( null );
51
52 // The asynchronous executor function, which is a wrapped version of the original callback.
53 const asyncExecutor = useRefSafeCallback( async ( ...args: A ) => {
54 if ( unmountedRef.current || isSSR() ) {
55 return null;
56 }
57
58 const currentExecutionUUID = uid();
59 prevExecutionUIDRef.current = currentExecutionUUID;
60
61 try {
62 // Prevent unnecessary state updates, keep loading state if the status is already 'loading'.
63 if ( asyncState.status !== 'loading' ) {
64 setAsyncState( {
65 status: 'loading'
66 } );
67 }
68
69 // Execute the asynchronous function.
70 const result = await callback( ...args );
71
72 // Update the state if the component is still mounted and the execution UUID matches the previous one, otherwise
73 // ignore the result and keep the previous state.
74 if ( !unmountedRef.current && prevExecutionUIDRef.current === currentExecutionUUID ) {
75 setAsyncState( {
76 status: 'success',
77 data: result
78 } );
79 }
80
81 return result;
82 } catch ( error: any ) {
83 console.error( error );
84
85 // Update the state if the component is still mounted and the execution UUID matches the previous one, otherwise
86 if ( !unmountedRef.current && prevExecutionUIDRef.current === currentExecutionUUID ) {
87 setAsyncState( {
88 status: 'error',
89 error
90 } );
91 }
92 }
93

Callers 2

useAsyncValueFunction · 0.85

Calls 2

useIsUnmountedRefFunction · 0.85
useRefSafeCallbackFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…