main
js 153 lines 3.5 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 * as React from 'react';
11 import {useContext} from 'react';
12
13 import {ProfilerContext} from './ProfilerContext';
14 import {StoreContext} from '../context';
15
16 import styles from './WhatChanged.css';
17 import HookChangeSummary from './HookChangeSummary';
18
19 type Props = {
20 fiberID: number,
21 displayMode?: 'detailed' | 'compact',
22 };
23
24 export default function WhatChanged({
25 fiberID,
26 displayMode = 'detailed',
27 }: Props): React.Node {
28 const {profilerStore} = useContext(StoreContext);
29 const {rootID, selectedCommitIndex} = useContext(ProfilerContext);
30
31 // TRICKY
32 // Handle edge case where no commit is selected because of a min-duration filter update.
33 // If the commit index is null, suspending for data below would throw an error.
34 // TODO (ProfilerContext) This check should not be necessary.
35 if (selectedCommitIndex === null) {
36 return null;
37 }
38
39 const {changeDescriptions} = profilerStore.getCommitData(
40 rootID as any as number,
41 selectedCommitIndex,
42 );
43
44 if (changeDescriptions === null) {
45 return null;
46 }
47
48 const changeDescription = changeDescriptions.get(fiberID);
49 if (changeDescription == null) {
50 return null;
51 }
52
53 const {context, didHooksChange, hooks, isFirstMount, props, state} =
54 changeDescription;
55
56 if (isFirstMount) {
57 return (
58 <div className={styles.Component}>
59 <label className={styles.Label}>Why did this render?</label>
60 <div className={styles.Item}>
61 This is the first time the component rendered.
62 </div>
63 </div>
64 );
65 }
66
67 const changes = [];
68
69 if (context === true) {
70 changes.push(
71 <div key="context" className={styles.Item}>
72 Context changed
73 </div>,
74 );
75 } else if (
76 typeof context === 'object' &&
77 context !== null &&
78 context.length !== 0
79 ) {
80 changes.push(
81 <div key="context" className={styles.Item}>
82 Context changed:
83 {context.map(key => (
84 <span key={key} className={styles.Key}>
85 {key}
86 </span>
87 ))}
88 </div>,
89 );
90 }
91
92 if (didHooksChange) {
93 if (Array.isArray(hooks)) {
94 changes.push(
95 <div key="hooks" className={styles.Item}>
96 <HookChangeSummary
97 hooks={hooks}
98 fiberID={fiberID}
99 state={state}
100 displayMode={displayMode}
101 />
102 </div>,
103 );
104 } else {
105 changes.push(
106 <div key="hooks" className={styles.Item}>
107 Hooks changed
108 </div>,
109 );
110 }
111 }
112
113 if (props !== null && props.length !== 0) {
114 changes.push(
115 <div key="props" className={styles.Item}>
116 Props changed:
117 {props.map(key => (
118 <span key={key} className={styles.Key}>
119 {key}
120 </span>
121 ))}
122 </div>,
123 );
124 }
125
126 if (state !== null && state.length !== 0) {
127 changes.push(
128 <div key="state" className={styles.Item}>
129 State changed:
130 {state.map(key => (
131 <span key={key} className={styles.Key}>
132 {key}
133 </span>
134 ))}
135 </div>,
136 );
137 }
138
139 if (changes.length === 0) {
140 changes.push(
141 <div key="nothing" className={styles.Item}>
142 The parent component rendered.
143 </div>,
144 );
145 }
146
147 return (
148 <div>
149 <label className={styles.Label}>Why did this render?</label>
150 {changes}
151 </div>
152 );
153 }