24
includesOnlyHydrationLanes,
25
includesOnlyOffscreenLanes,
26
includesOnlyHydrationOrOffscreenLanes,
27
+ includesSomeLane,
28
} from './ReactFiberLane';
29
30
import {
105
reusableComponentOptions.start = startTime;
106
reusableComponentOptions.end = endTime;
107
reusableComponentDevToolDetails.color = 'warning';
108
+ reusableComponentDevToolDetails.tooltipText = trigger;
109
reusableComponentDevToolDetails.properties = null;
110
const debugTask = fiber._debugTask;
111
if (__DEV__ && debugTask) {
155
logComponentTrigger(fiber, startTime, endTime, 'Disconnect');
156
}
157
158
+let alreadyWarnedForDeepEquality = false;
159
+
160
+export function pushDeepEquality(): boolean {
161
+ if (__DEV__) {
162
+ // If this is true then we don't reset it to false because we're tracking if any
163
+ // parent already warned about having deep equality props in this subtree.
164
+ return alreadyWarnedForDeepEquality;
165
+ }
166
+ return false;
167
+}
168
+
169
+export function popDeepEquality(prev: boolean): void {
170
+ if (__DEV__) {
171
+ alreadyWarnedForDeepEquality = prev;
172
+ }
173
+}
174
+
175
const reusableComponentDevToolDetails = {
176
color: 'primary',
177
properties: (null: null | Array<[string, string]>),
178
+ tooltipText: '',
179
track: COMPONENTS_TRACK,
180
};
181
+
182
const reusableComponentOptions = {
183
start: -0,
184
end: -0,
189
190
const resuableChangedPropsEntry = ['Changed Props', ''];
191
192
+const DEEP_EQUALITY_WARNING =
193
+ 'This component received deeply equal props. It might benefit from useMemo or the React Compiler in its owner.';
194
+
195
+const reusableDeeplyEqualPropsEntry = ['Changed Props', DEEP_EQUALITY_WARNING];
196
+
197
export function logComponentRender(
198
fiber: Fiber,
199
startTime: number,
200
endTime: number,
201
wasHydrated: boolean,
202
+ committedLanes: Lanes,
203
): void {
204
const name = getComponentNameFromFiber(fiber);
205
if (name === null) {
238
) {
239
// If this is an update, we'll diff the props and emit which ones changed.
240
const properties: Array<[string, string]> = [resuableChangedPropsEntry];
214
- addObjectDiffToProperties(
241
+ const isDeeplyEqual = addObjectDiffToProperties(
242
alternate.memoizedProps,
243
props,
244
properties,
245
0,
246
);
247
if (properties.length > 1) {
248
+ if (
249
+ isDeeplyEqual &&
250
+ !alreadyWarnedForDeepEquality &&
251
+ !includesSomeLane(alternate.lanes, committedLanes) &&
252
+ (fiber.actualDuration: any) > 100
253
+ ) {
254
+ alreadyWarnedForDeepEquality = true;
255
+ // This is the first component in a subtree which rerendered with deeply equal props
256
+ // and didn't have its own work scheduled and took a non-trivial amount of time.
257
+ // We highlight this for further inspection.
258
+ // Note that we only consider this case if properties.length > 1 which it will only
259
+ // be if we have emitted any diffs. We'd only emit diffs if there were any nested
260
+ // equal objects. Therefore, we don't warn for simple shallow equality.
261
+ properties[0] = reusableDeeplyEqualPropsEntry;
262
+ reusableComponentDevToolDetails.color = 'warning';
263
+ reusableComponentDevToolDetails.tooltipText = DEEP_EQUALITY_WARNING;
264
+ } else {
265
+ reusableComponentDevToolDetails.color = color;
266
+ reusableComponentDevToolDetails.tooltipText = name;
267
+ }
268
+ reusableComponentDevToolDetails.properties = properties;
269
reusableComponentOptions.start = startTime;
270
reusableComponentOptions.end = endTime;
223
- reusableComponentDevToolDetails.color = color;
224
- reusableComponentDevToolDetails.properties = properties;
271
debugTask.run(
272
// $FlowFixMe[method-unbinding]
273
performance.measure.bind(