-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathrender-hook.tsx
65 lines (52 loc) · 1.82 KB
/
render-hook.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import * as React from 'react';
import { renderInternal } from './render';
export type RenderHookResult<Result, Props> = {
rerender: (props: Props) => void;
result: React.MutableRefObject<Result>;
unmount: () => void;
};
export type RenderHookOptions<Props> = {
/**
* The initial props to pass to the hook.
*/
initialProps?: Props;
/**
* Pass a React Component as the wrapper option to have it rendered around the inner element. This is most useful for creating
* reusable custom render functions for common data providers.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
wrapper?: React.ComponentType<any>;
/**
* Set to `false` to disable concurrent rendering.
* Otherwise `renderHook` will default to concurrent rendering.
*/
concurrentRoot?: boolean;
};
export function renderHook<Result, Props>(
hookToRender: (props: Props) => Result,
options?: RenderHookOptions<Props>,
): RenderHookResult<Result, Props> {
const { initialProps, ...renderOptions } = options ?? {};
const result: React.MutableRefObject<Result | null> = React.createRef();
function TestComponent({ hookProps }: { hookProps: Props }) {
const renderResult = hookToRender(hookProps);
React.useEffect(() => {
result.current = renderResult;
});
return null;
}
const { rerender: componentRerender, unmount } = renderInternal(
// @ts-expect-error since option can be undefined, initialProps can be undefined when it should'nt
<TestComponent hookProps={initialProps} />,
renderOptions,
);
function rerender(hookProps: Props) {
return componentRerender(<TestComponent hookProps={hookProps} />);
}
return {
// Result should already be set after the first render effects are run.
result: result as React.MutableRefObject<Result>,
rerender,
unmount,
};
}