Alpha-sort props/state/context keys
Brian Vaughn committed
Aug 19, 2019 at 09:17 UTC
01b1e7e2cf5cd1fb84318b32a6cb236e6d9b35ef
4 files changed
+43
-7
src/devtools/views/Components/HooksTree.js
+3
@@ -164,6 +164,7 @@ function HookView({
164
) : (
165
<KeyValue
166
depth={1}
167
+ alphaSort={false}
168
inspectPath={inspectPath}
169
name="subHooks"
170
path={path.concat(['subHooks'])}
@@ -186,6 +187,7 @@ function HookView({
187
<div className={styles.Children} hidden={!isOpen}>
188
<KeyValue
189
depth={1}
190
+ alphaSort={false}
191
inspectPath={inspectPath}
192
name="DebugValue"
193
path={path.concat(['value'])}
@@ -242,6 +244,7 @@ function HookView({
244
<div className={styles.Hook}>
245
<KeyValue
246
depth={1}
247
+ alphaSort={false}
248
inspectPath={inspectPath}
249
name={name}
250
overrideValueFn={overrideValueFn}
src/devtools/views/Components/InspectedElementTree.js
+10
-4
@@ -5,7 +5,7 @@ import React, { useCallback } from 'react';
5
import Button from '../Button';
6
import ButtonIcon from '../ButtonIcon';
7
import KeyValue from './KeyValue';
8
-import { serializeDataForCopy } from '../utils';
8
+import { alphaSortEntries, serializeDataForCopy } from '../utils';
9
import styles from './InspectedElementTree.css';
10
11
import type { InspectPath } from './SelectedElement';
@@ -27,7 +27,12 @@ export default function InspectedElementTree({
27
overrideValueFn,
28
showWhenEmpty = false,
29
}: Props) {
30
- const isEmpty = data === null || Object.keys(data).length === 0;
30
+ const entries = data != null ? Object.entries(data) : null;
31
+ if (entries !== null) {
32
+ entries.sort(alphaSortEntries);
33
+ }
34
+
35
+ const isEmpty = entries === null || entries.length === 0;
36
37
const handleCopy = useCallback(() => copy(serializeDataForCopy(data)), [
38
data,
@@ -48,15 +53,16 @@ export default function InspectedElementTree({
53
</div>
54
{isEmpty && <div className={styles.Empty}>None</div>}
55
{!isEmpty &&
51
- Object.keys((data: any)).map(name => (
56
+ (entries: any).map(([name, value]) => (
57
<KeyValue
58
key={name}
59
+ alphaSort={true}
60
depth={1}
61
inspectPath={inspectPath}
62
name={name}
63
overrideValueFn={overrideValueFn}
64
path={[name]}
59
- value={(data: any)[name]}
65
+ value={value}
66
/>
67
))}
68
</div>
src/devtools/views/Components/KeyValue.js
+15
-3
@@ -4,7 +4,7 @@ import React, { useEffect, useRef, useState } from 'react';
4
import type { Element } from 'react';
5
import EditableValue from './EditableValue';
6
import ExpandCollapseToggle from './ExpandCollapseToggle';
7
-import { getMetaValueLabel } from '../utils';
7
+import { alphaSortEntries, getMetaValueLabel } from '../utils';
8
import { meta } from '../../../hydration';
9
import styles from './KeyValue.css';
10
@@ -13,6 +13,7 @@ import type { InspectPath } from './SelectedElement';
13
type OverrideValueFn = (path: Array<string | number>, value: any) => void;
14
15
type KeyValueProps = {|
16
+ alphaSort: boolean,
17
depth: number,
18
hidden?: boolean,
19
inspectPath?: InspectPath,
@@ -24,6 +25,7 @@ type KeyValueProps = {|
25
|};
26
27
export default function KeyValue({
28
+ alphaSort,
29
depth,
30
inspectPath,
31
isReadOnly,
@@ -127,6 +129,7 @@ export default function KeyValue({
129
children = value.map((innerValue, index) => (
130
<KeyValue
131
key={index}
132
+ alphaSort={alphaSort}
133
depth={depth + 1}
134
inspectPath={inspectPath}
135
isReadOnly={isReadOnly}
@@ -162,15 +165,24 @@ export default function KeyValue({
165
</div>
166
);
167
} else {
165
- const hasChildren = Object.entries(value).length > 0;
168
+ // TRICKY
169
+ // It's important to use Object.entries() rather than Object.keys()
170
+ // because of the hidden meta Symbols used for hydration and unserializable values.
171
+ const entries = Object.entries(value);
172
+ if (alphaSort) {
173
+ entries.sort(alphaSortEntries);
174
+ }
175
+
176
+ const hasChildren = entries.length > 0;
177
const displayName = value.hasOwnProperty(meta.unserializable)
178
? getMetaValueLabel(value)
179
: 'Object';
180
181
let areChildrenReadOnly = isReadOnly || !!value[meta.readonly];
171
- children = Object.entries(value).map<Element<any>>(([name, value]) => (
182
+ children = entries.map<Element<any>>(([name, value]) => (
183
<KeyValue
184
key={name}
185
+ alphaSort={alphaSort}
186
depth={depth + 1}
187
inspectPath={inspectPath}
188
isReadOnly={areChildrenReadOnly}
src/devtools/views/utils.js
+15
@@ -5,6 +5,21 @@ import { meta } from '../../hydration';
5
6
import type { HooksTree } from 'src/backend/types';
7
8
+export function alphaSortEntries(
9
+ entryA: [string, mixed],
10
+ entryB: [string, mixed]
11
+): number {
12
+ const a = entryA[0];
13
+ const b = entryB[0];
14
+ if ('' + +a === a) {
15
+ if ('' + +b !== b) {
16
+ return -1;
17
+ }
18
+ return +a < +b ? -1 : 1;
19
+ }
20
+ return a < b ? -1 : 1;
21
+}
22
+
23
export function createRegExp(string: string): RegExp {
24
// Allow /regex/ syntax with optional last /
25
if (string[0] === '/') {