1
1
import * as React from 'react' ;
2
2
3
- import { renderInternal } from './render' ;
3
+ import render from './render' ;
4
+ import renderAsync from './render-async' ;
4
5
5
6
export type RenderHookResult < Result , Props > = {
7
+ result : React . RefObject < Result > ;
6
8
rerender : ( props : Props ) => void ;
7
- result : React . MutableRefObject < Result > ;
8
9
unmount : ( ) => void ;
9
10
} ;
10
11
12
+ export type RenderHookAsyncResult < Result , Props > = {
13
+ result : React . RefObject < Result > ;
14
+ rerender : ( props : Props ) => Promise < void > ;
15
+ unmount : ( ) => Promise < void > ;
16
+ } ;
17
+
11
18
export type RenderHookOptions < Props > = {
12
19
/**
13
20
* The initial props to pass to the hook.
@@ -32,34 +39,58 @@ export function renderHook<Result, Props>(
32
39
hookToRender : ( props : Props ) => Result ,
33
40
options ?: RenderHookOptions < Props > ,
34
41
) : RenderHookResult < Result , Props > {
42
+ const result : React . RefObject < Result | null > = React . createRef ( ) ;
43
+
44
+ function HookContainer ( { hookProps } : { hookProps : Props } ) {
45
+ const renderResult = hookToRender ( hookProps ) ;
46
+ React . useEffect ( ( ) => {
47
+ result . current = renderResult ;
48
+ } ) ;
49
+
50
+ return null ;
51
+ }
52
+
35
53
const { initialProps, ...renderOptions } = options ?? { } ;
54
+ const { rerender : rerenderComponent , unmount } = render (
55
+ // @ts -expect-error since option can be undefined, initialProps can be undefined when it should'nt
56
+ < HookContainer hookProps = { initialProps } /> ,
57
+ renderOptions ,
58
+ ) ;
36
59
37
- const result : React . MutableRefObject < Result | null > = React . createRef ( ) ;
60
+ return {
61
+ // Result should already be set after the first render effects are run.
62
+ result : result as React . RefObject < Result > ,
63
+ rerender : ( hookProps : Props ) => rerenderComponent ( < HookContainer hookProps = { hookProps } /> ) ,
64
+ unmount,
65
+ } ;
66
+ }
67
+
68
+ export async function renderHookAsync < Result , Props > (
69
+ hookToRender : ( props : Props ) => Result ,
70
+ options ?: RenderHookOptions < Props > ,
71
+ ) : Promise < RenderHookAsyncResult < Result , Props > > {
72
+ const result : React . RefObject < Result | null > = React . createRef ( ) ;
38
73
39
74
function TestComponent ( { hookProps } : { hookProps : Props } ) {
40
75
const renderResult = hookToRender ( hookProps ) ;
41
-
42
76
React . useEffect ( ( ) => {
43
77
result . current = renderResult ;
44
78
} ) ;
45
79
46
80
return null ;
47
81
}
48
82
49
- const { rerender : componentRerender , unmount } = renderInternal (
83
+ const { initialProps, ...renderOptions } = options ?? { } ;
84
+ const { rerenderAsync : rerenderComponentAsync , unmountAsync } = await renderAsync (
50
85
// @ts -expect-error since option can be undefined, initialProps can be undefined when it should'nt
51
86
< TestComponent hookProps = { initialProps } /> ,
52
87
renderOptions ,
53
88
) ;
54
89
55
- function rerender ( hookProps : Props ) {
56
- return componentRerender ( < TestComponent hookProps = { hookProps } /> ) ;
57
- }
58
-
59
90
return {
60
91
// Result should already be set after the first render effects are run.
61
- result : result as React . MutableRefObject < Result > ,
62
- rerender,
63
- unmount,
92
+ result : result as React . RefObject < Result > ,
93
+ rerender : ( hookProps : Props ) => rerenderComponentAsync ( < TestComponent hookProps = { hookProps } /> ) ,
94
+ unmount : unmountAsync ,
64
95
} ;
65
96
}
0 commit comments