main
js 229 lines 6.43 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import type {Fiber} from './ReactInternalTypes';
11 import type {LazyComponent} from 'react/src/ReactLazy';
12 import type {Effect} from './ReactFiberHooks';
13 import type {CapturedValue} from './ReactCapturedValue';
14
15 import {isRendering, setIsRendering} from './ReactCurrentFiber';
16 import {captureCommitPhaseError} from './ReactFiberWorkLoop';
17
18 // These indirections exists so we can exclude its stack frame in DEV (and anything below it).
19 // TODO: Consider marking the whole bundle instead of these boundaries.
20
21 const callComponent = {
22 react_stack_bottom_frame: function <Props, Arg, R>(
23 Component: (p: Props, arg: Arg) => R,
24 props: Props,
25 secondArg: Arg,
26 ): R {
27 const wasRendering = isRendering;
28 setIsRendering(true);
29 try {
30 const result = Component(props, secondArg);
31 return result;
32 } finally {
33 setIsRendering(wasRendering);
34 }
35 },
36 };
37
38 export const callComponentInDEV: <Props, Arg, R>(
39 Component: (p: Props, arg: Arg) => R,
40 props: Props,
41 secondArg: Arg,
42 ) => R = __DEV__
43 ? // We use this technique to trick minifiers to preserve the function name.
44 (callComponent.react_stack_bottom_frame.bind(callComponent) as any)
45 : (null as any);
46
47 interface ClassInstance<R> {
48 render(): R;
49 componentDidMount(): void;
50 componentDidUpdate(
51 prevProps: Object,
52 prevState: Object,
53 snaphot: Object,
54 ): void;
55 componentDidCatch(error: mixed, errorInfo: {componentStack: string}): void;
56 componentWillUnmount(): void;
57 }
58
59 const callRender = {
60 react_stack_bottom_frame: function <R>(instance: ClassInstance<R>): R {
61 const wasRendering = isRendering;
62 setIsRendering(true);
63 try {
64 const result = instance.render();
65 return result;
66 } finally {
67 setIsRendering(wasRendering);
68 }
69 },
70 };
71
72 export const callRenderInDEV: <R>(instance: ClassInstance<R>) => R => R =
73 __DEV__
74 ? // We use this technique to trick minifiers to preserve the function name.
75 (callRender.react_stack_bottom_frame.bind(callRender) as any)
76 : (null as any);
77
78 const callComponentDidMount = {
79 react_stack_bottom_frame: function (
80 finishedWork: Fiber,
81 instance: ClassInstance<any>,
82 ): void {
83 try {
84 instance.componentDidMount();
85 } catch (error) {
86 captureCommitPhaseError(finishedWork, finishedWork.return, error);
87 }
88 },
89 };
90
91 export const callComponentDidMountInDEV: (
92 finishedWork: Fiber,
93 instance: ClassInstance<any>,
94 ) => void = __DEV__
95 ? // We use this technique to trick minifiers to preserve the function name.
96 (callComponentDidMount.react_stack_bottom_frame.bind(
97 callComponentDidMount,
98 ) as any)
99 : (null as any);
100
101 const callComponentDidUpdate = {
102 react_stack_bottom_frame: function (
103 finishedWork: Fiber,
104 instance: ClassInstance<any>,
105 prevProps: Object,
106 prevState: Object,
107 snapshot: Object,
108 ): void {
109 try {
110 instance.componentDidUpdate(prevProps, prevState, snapshot);
111 } catch (error) {
112 captureCommitPhaseError(finishedWork, finishedWork.return, error);
113 }
114 },
115 };
116
117 export const callComponentDidUpdateInDEV: (
118 finishedWork: Fiber,
119 instance: ClassInstance<any>,
120 prevProps: Object,
121 prevState: Object,
122 snaphot: Object,
123 ) => void = __DEV__
124 ? // We use this technique to trick minifiers to preserve the function name.
125 (callComponentDidUpdate.react_stack_bottom_frame.bind(
126 callComponentDidUpdate,
127 ) as any)
128 : (null as any);
129
130 const callComponentDidCatch = {
131 react_stack_bottom_frame: function (
132 instance: ClassInstance<any>,
133 errorInfo: CapturedValue<mixed>,
134 ): void {
135 const error = errorInfo.value;
136 const stack = errorInfo.stack;
137 instance.componentDidCatch(error, {
138 componentStack: stack !== null ? stack : '',
139 });
140 },
141 };
142
143 export const callComponentDidCatchInDEV: (
144 instance: ClassInstance<any>,
145 errorInfo: CapturedValue<mixed>,
146 ) => void = __DEV__
147 ? // We use this technique to trick minifiers to preserve the function name.
148 (callComponentDidCatch.react_stack_bottom_frame.bind(
149 callComponentDidCatch,
150 ) as any)
151 : (null as any);
152
153 const callComponentWillUnmount = {
154 react_stack_bottom_frame: function (
155 current: Fiber,
156 nearestMountedAncestor: Fiber | null,
157 instance: ClassInstance<any>,
158 ): void {
159 try {
160 instance.componentWillUnmount();
161 } catch (error) {
162 captureCommitPhaseError(current, nearestMountedAncestor, error);
163 }
164 },
165 };
166
167 export const callComponentWillUnmountInDEV: (
168 current: Fiber,
169 nearestMountedAncestor: Fiber | null,
170 instance: ClassInstance<any>,
171 ) => void = __DEV__
172 ? // We use this technique to trick minifiers to preserve the function name.
173 (callComponentWillUnmount.react_stack_bottom_frame.bind(
174 callComponentWillUnmount,
175 ) as any)
176 : (null as any);
177
178 const callCreate = {
179 react_stack_bottom_frame: function (
180 effect: Effect,
181 ): (() => void) | {...} | void | null {
182 const create = effect.create;
183 const inst = effect.inst;
184 const destroy = create();
185 inst.destroy = destroy;
186 return destroy;
187 },
188 };
189
190 export const callCreateInDEV: (effect: Effect) => (() => void) | void = __DEV__
191 ? // We use this technique to trick minifiers to preserve the function name.
192 (callCreate.react_stack_bottom_frame.bind(callCreate) as any)
193 : (null as any);
194
195 const callDestroy = {
196 react_stack_bottom_frame: function (
197 current: Fiber,
198 nearestMountedAncestor: Fiber | null,
199 destroy: () => void,
200 ): void {
201 try {
202 destroy();
203 } catch (error) {
204 captureCommitPhaseError(current, nearestMountedAncestor, error);
205 }
206 },
207 };
208
209 export const callDestroyInDEV: (
210 current: Fiber,
211 nearestMountedAncestor: Fiber | null,
212 destroy: (() => void) | (({...}) => void),
213 ) => void = __DEV__
214 ? // We use this technique to trick minifiers to preserve the function name.
215 (callDestroy.react_stack_bottom_frame.bind(callDestroy) as any)
216 : (null as any);
217
218 const callLazyInit = {
219 react_stack_bottom_frame: function (lazy: LazyComponent<any, any>): any {
220 const payload = lazy._payload;
221 const init = lazy._init;
222 return init(payload);
223 },
224 };
225
226 export const callLazyInitInDEV: (lazy: LazyComponent<any, any>) => any = __DEV__
227 ? // We use this technique to trick minifiers to preserve the function name.
228 (callLazyInit.react_stack_bottom_frame.bind(callLazyInit) as any)
229 : (null as any);