Fixed owners stack direction and added current element to stack
Brian Vaughn committed
May 9, 2019 at 18:11 UTC
7160f6f584d3eb487230fe64b4a76e5086eb7cec
6 files changed
+106
-15
src/__tests__/__snapshots__/ownersListContext-test.js.snap
+30
-4
@@ -9,13 +9,17 @@ exports[`OwnersListContext should fetch the owners list for the selected element
9
10
exports[`OwnersListContext should fetch the owners list for the selected element that includes filtered components: owners for "Child" 1`] = `
11
Array [
12
+ Object {
13
+ "displayName": "Grandparent",
14
+ "id": 7,
15
+ },
16
Object {
17
"displayName": "Parent",
18
"id": 9,
19
},
20
Object {
17
- "displayName": "Grandparent",
18
- "id": 7,
21
+ "displayName": "Child",
22
+ "id": 8,
23
},
24
]
25
`;
@@ -30,13 +34,17 @@ exports[`OwnersListContext should fetch the owners list for the selected element
34
35
exports[`OwnersListContext should fetch the owners list for the selected element: owners for "Child" 1`] = `
36
Array [
37
+ Object {
38
+ "displayName": "Grandparent",
39
+ "id": 2,
40
+ },
41
Object {
42
"displayName": "Parent",
43
"id": 3,
44
},
45
Object {
38
- "displayName": "Grandparent",
39
- "id": 2,
46
+ "displayName": "Child",
47
+ "id": 4,
48
},
49
]
50
`;
@@ -47,5 +55,23 @@ Array [
55
"displayName": "Grandparent",
56
"id": 2,
57
},
58
+ Object {
59
+ "displayName": "Parent",
60
+ "id": 3,
61
+ },
62
+]
63
+`;
64
+
65
+exports[`OwnersListContext should include the current element even if there are no other owners: mount 1`] = `
66
+[root]
67
+ <Grandparent>
68
+`;
69
+
70
+exports[`OwnersListContext should include the current element even if there are no other owners: owners for "Grandparent" 1`] = `
71
+Array [
72
+ Object {
73
+ "displayName": "Grandparent",
74
+ "id": 5,
75
+ },
76
]
77
`;
src/__tests__/ownersListContext-test.js
+44
@@ -163,4 +163,48 @@ describe('OwnersListContext', () => {
163
164
done();
165
});
166
+
167
+ it('should include the current element even if there are no other owners', async done => {
168
+ store.componentFilters = [utils.createDisplayNameFilter('^Parent$')];
169
+
170
+ const Grandparent = () => <Parent />;
171
+ const Parent = () => null;
172
+
173
+ utils.act(() =>
174
+ ReactDOM.render(<Grandparent />, document.createElement('div'))
175
+ );
176
+
177
+ expect(store).toMatchSnapshot('mount');
178
+
179
+ const grandparent = ((store.getElementAtIndex(0): any): Element);
180
+
181
+ let didFinish = false;
182
+
183
+ function Suspender({ owner }) {
184
+ const read = React.useContext(OwnersListContext);
185
+ const owners = read(owner.id);
186
+ expect(owners).toMatchSnapshot(
187
+ `owners for "${(owner && owner.displayName) || ''}"`
188
+ );
189
+ didFinish = true;
190
+ return null;
191
+ }
192
+
193
+ await utils.actSuspense(
194
+ () =>
195
+ TestRenderer.create(
196
+ <Contexts defaultOwnerID={grandparent.id}>
197
+ <React.Suspense fallback={null}>
198
+ <Suspender owner={grandparent} />
199
+ </React.Suspense>
200
+ </Contexts>
201
+ ),
202
+ 3
203
+ );
204
+ expect(didFinish).toBe(true);
205
+
206
+ done();
207
+ });
208
+
209
+ // TODO (owners) Verify that if an Element in the list is unmounted the stack is updated.
210
});
src/backend/renderer.js
+23
-4
@@ -1696,12 +1696,17 @@ export function attach(
1696
1697
const { _debugOwner } = fiber;
1698
1699
- let owners = null;
1699
+ const owners = [
1700
+ {
1701
+ displayName: getDisplayNameForFiber(fiber) || 'Unknown',
1702
+ id,
1703
+ },
1704
+ ];
1705
+
1706
if (_debugOwner) {
1701
- owners = [];
1707
let owner = _debugOwner;
1708
while (owner !== null) {
1704
- owners.push({
1709
+ owners.unshift({
1710
displayName: getDisplayNameForFiber(owner) || 'Unknown',
1711
id: getFiberID(getPrimaryFiber(owner)),
1712
});
@@ -1719,6 +1724,7 @@ export function attach(
1724
}
1725
1726
const {
1727
+ _debugOwner,
1728
_debugSource,
1729
stateNode,
1730
memoizedProps,
@@ -1790,6 +1796,19 @@ export function attach(
1796
context = { value: context };
1797
}
1798
1799
+ let owners = null;
1800
+ if (_debugOwner) {
1801
+ owners = [];
1802
+ let owner = _debugOwner;
1803
+ while (owner !== null) {
1804
+ owners.push({
1805
+ displayName: getDisplayNameForFiber(owner) || 'Unknown',
1806
+ id: getFiberID(getPrimaryFiber(owner)),
1807
+ });
1808
+ owner = owner._debugOwner || null;
1809
+ }
1810
+ }
1811
+
1812
const isTimedOutSuspense =
1813
tag === SuspenseComponent && memoizedState !== null;
1814
@@ -1825,7 +1844,7 @@ export function attach(
1844
state: usesHooks ? null : memoizedState,
1845
1846
// List of owners
1828
- owners: getOwnersList(id),
1847
+ owners,
1848
1849
// Location of component in source coude.
1850
source: _debugSource,
src/devtools/views/Components/OwnersStack.js
+7
-5
@@ -45,7 +45,7 @@ type State = {|
45
function dialogReducer(state, action) {
46
switch (action.type) {
47
case 'UPDATE_OWNER_ID':
48
- const selectedIndex = state.owners.findIndex(
48
+ const selectedIndex = action.owners.findIndex(
49
owner => owner.id === action.ownerID
50
);
51
return {
@@ -71,10 +71,11 @@ export default function OwnerStack() {
71
const [state, dispatch] = useReducer<State, Action>(dialogReducer, {
72
ownerID: null,
73
owners: [],
74
- selectedIndex: -1,
74
+ selectedIndex: 0,
75
});
76
77
- // TODO (owners) Explain this and use reducer with ownerID too to avoid inf. loop
77
+ // When an owner is selected, we either need to update the selected index, or we need to fetch a new list of owners.
78
+ // We use a reducer here so that we can avoid fetching a new list unless the owner ID has actually changed.
79
if (ownerID === null) {
80
dispatch({
81
type: 'UPDATE_OWNER_ID',
@@ -82,11 +83,12 @@ export default function OwnerStack() {
83
owners: [],
84
});
85
} else if (ownerID !== state.ownerID) {
85
- const isInList = state.owners.findIndex(owner => owner.id === ownerID) >= 0;
86
+ const isInStore =
87
+ state.owners.findIndex(owner => owner.id === ownerID) >= 0;
88
dispatch({
89
type: 'UPDATE_OWNER_ID',
90
ownerID,
89
- owners: isInList ? state.owners : read(ownerID) || [],
91
+ owners: isInStore ? state.owners : read(ownerID) || [],
92
});
93
}
94
src/devtools/views/Components/SelectedElement.js
+1
-1
@@ -304,7 +304,7 @@ function InspectedElementView({
304
{owners.map(owner => (
305
<OwnerView
306
key={owner.id}
307
- displayName={owner.displayName}
307
+ displayName={owner.displayName || 'Unknown'}
308
id={owner.id}
309
isInStore={store.containsElement(owner.id)}
310
/>
src/devtools/views/Components/types.js
+1
-1
@@ -31,7 +31,7 @@ export type Element = {|
31
|};
32
33
export type Owner = {|
34
- displayName: string,
34
+ displayName: string | null,
35
id: number,
36
|};
37