11import * as React from 'react' ;
22
3- import { renderInternal } from './render' ;
3+ import render from './render' ;
4+ import renderAsync from './render-async' ;
45
56export type RenderHookResult < Result , Props > = {
7+ result : React . RefObject < Result > ;
68 rerender : ( props : Props ) => void ;
7- result : React . MutableRefObject < Result > ;
89 unmount : ( ) => void ;
910} ;
1011
12+ export type RenderHookAsyncResult < Result , Props > = {
13+ result : React . RefObject < Result > ;
14+ rerender : ( props : Props ) => Promise < void > ;
15+ unmount : ( ) => Promise < void > ;
16+ } ;
17+
1118export type RenderHookOptions < Props > = {
1219 /**
1320 * The initial props to pass to the hook.
@@ -32,34 +39,58 @@ export function renderHook<Result, Props>(
3239 hookToRender : ( props : Props ) => Result ,
3340 options ?: RenderHookOptions < Props > ,
3441) : 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+
3553 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+ ) ;
3659
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 ( ) ;
3873
3974 function TestComponent ( { hookProps } : { hookProps : Props } ) {
4075 const renderResult = hookToRender ( hookProps ) ;
41-
4276 React . useEffect ( ( ) => {
4377 result . current = renderResult ;
4478 } ) ;
4579
4680 return null ;
4781 }
4882
49- const { rerender : componentRerender , unmount } = renderInternal (
83+ const { initialProps, ...renderOptions } = options ?? { } ;
84+ const { rerenderAsync : rerenderComponentAsync , unmountAsync } = await renderAsync (
5085 // @ts -expect-error since option can be undefined, initialProps can be undefined when it should'nt
5186 < TestComponent hookProps = { initialProps } /> ,
5287 renderOptions ,
5388 ) ;
5489
55- function rerender ( hookProps : Props ) {
56- return componentRerender ( < TestComponent hookProps = { hookProps } /> ) ;
57- }
58-
5990 return {
6091 // 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 ,
6495 } ;
6596}
0 commit comments