@samitouri / QOS-React-2 / commits / 01b1e7e2cf

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] === '/') {