-
-
Notifications
You must be signed in to change notification settings - Fork 9.1k
/
render.tsx
81 lines (66 loc) · 2.14 KB
/
render.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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import { document, FRAMEWORK_OPTIONS } from 'global';
import React, { Component, FunctionComponent, ReactElement, StrictMode, Fragment } from 'react';
import ReactDOM from 'react-dom';
import { StoryContext, RenderContext } from './types';
const rootElement = document ? document.getElementById('root') : null;
const render = (node: ReactElement, el: Element) =>
new Promise((resolve) => {
ReactDOM.render(node, el, resolve);
});
class ErrorBoundary extends Component<{
showException: (err: Error) => void;
showMain: () => void;
}> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidMount() {
const { hasError } = this.state;
const { showMain } = this.props;
if (!hasError) {
showMain();
}
}
componentDidCatch(err: Error) {
const { showException } = this.props;
// message partially duplicates stack, strip it
showException(err);
}
render() {
const { hasError } = this.state;
const { children } = this.props;
return hasError ? null : children;
}
}
const Wrapper = FRAMEWORK_OPTIONS?.strictMode ? StrictMode : Fragment;
export default async function renderMain({
storyContext,
unboundStoryFn,
showMain,
showException,
forceRender,
targetDOMNode = rootElement,
}: RenderContext) {
const Story = unboundStoryFn as FunctionComponent<StoryContext>;
const content = (
<ErrorBoundary showMain={showMain} showException={showException}>
<Story {...storyContext} />
</ErrorBoundary>
);
// For React 15, StrictMode & Fragment doesn't exists.
const element = Wrapper ? <Wrapper>{content}</Wrapper> : content;
// We need to unmount the existing set of components in the DOM node.
// Otherwise, React may not recreate instances for every story run.
// This could leads to issues like below:
// https://github.com/storybookjs/react-storybook/issues/81
// But forceRender means that it's the same story, so we want too keep the state in that case.
if (!forceRender) {
try {
ReactDOM.unmountComponentAtNode(targetDOMNode);
} catch (e) {
//
}
}
await render(element, targetDOMNode);
}