@samitouri / QOS-React-2 / commits / bc4e8950f6

Updated test code to include a deeply nested DIV

Brian Vaughn committed Feb 27, 2019 at 13:05 UTC bc4e8950f6d0d33399b9b86fdc9129ca0d5d2295
10 files changed +186 -175
shells/dev/app/DeeplyNestedComponents/index.js new
+34
@@ -0,0 +1,34 @@
1 +// @flow
2 +
3 +import React, { Fragment } from 'react';
4 +
5 +function wrapWithHoc(Component, index) {
6 + function HOC() {
7 + return <Component />;
8 + }
9 + HOC.displayName = `HOC-${index}`;
10 + return HOC;
11 +}
12 +
13 +function wrapWithNested(Component, times) {
14 + for (let i = 0; i < times; i++) {
15 + Component = wrapWithHoc(Component, i);
16 + }
17 +
18 + return Component;
19 +}
20 +
21 +function Nested() {
22 + return <div>Deeply nested div</div>;
23 +}
24 +
25 +const DeeplyNested = wrapWithNested(Nested, 100);
26 +
27 +export default function DeeplyNestedComponents() {
28 + return (
29 + <Fragment>
30 + <h1>Deeply nested component</h1>
31 + <DeeplyNested />
32 + </Fragment>
33 + );
34 +}
shells/dev/app/EditableProps/EditableProps.js deleted
-132
@@ -1,132 +0,0 @@
1 -// @flow
2 -
3 -import React, {
4 - createContext,
5 - Component,
6 - Fragment,
7 - useCallback,
8 - useDebugValue,
9 - useEffect,
10 - useReducer,
11 - useState,
12 -} from 'react';
13 -import styles from './EditableProps.css';
14 -
15 -const initialData = { foo: 'FOO', bar: 'BAR' };
16 -
17 -function reducer(state, action) {
18 - switch (action.type) {
19 - case 'swap':
20 - return { foo: state.bar, bar: state.foo };
21 - default:
22 - throw new Error();
23 - }
24 -}
25 -
26 -type StatefulFunctionProps = {| name: string |};
27 -
28 -function StatefulFunction({ name }: StatefulFunctionProps) {
29 - const [count, updateCount] = useState(0);
30 - const debouncedCount = useDebounce(count, 1000);
31 - const handleUpdateCountClick = useCallback(() => updateCount(count + 1), [
32 - count,
33 - ]);
34 -
35 - const [data, dispatch] = useReducer(reducer, initialData);
36 - const handleUpdateReducerClick = useCallback(
37 - () => dispatch({ type: 'swap' }),
38 - []
39 - );
40 -
41 - return (
42 - <Fragment>
43 - <li>Name: {name}</li>
44 - <li>
45 - <button onClick={handleUpdateCountClick}>
46 - Debounced count: {debouncedCount}
47 - </button>
48 - </li>
49 - <li>
50 - Reducer state: foo "{data.foo}", bar "{data.bar}"
51 - </li>
52 - <li>
53 - <button onClick={handleUpdateReducerClick}>Swap reducer values</button>
54 - </li>
55 - </Fragment>
56 - );
57 -}
58 -
59 -const BoolContext = createContext(true);
60 -BoolContext.displayName = 'BoolContext';
61 -
62 -type Props = {| name: string, toggle: boolean |};
63 -type State = {| cities: Array<string>, state: string |};
64 -
65 -class StatefulClass extends Component<Props, State> {
66 - static contextType = BoolContext;
67 -
68 - state: State = {
69 - cities: ['San Francisco', 'San Jose'],
70 - state: 'California',
71 - };
72 -
73 - handleChange = ({ target }) =>
74 - this.setState({
75 - state: target.value,
76 - });
77 -
78 - render() {
79 - return (
80 - <Fragment>
81 - <li>Name: {this.props.name}</li>
82 - <li>Toggle: {this.props.toggle ? 'true' : 'false'}</li>
83 - <li>
84 - State: <input value={this.state.state} onChange={this.handleChange} />
85 - </li>
86 - <li>Cities: {this.state.cities.join(', ')}</li>
87 - <li>Context: {this.context ? 'true' : 'false'}</li>
88 - </Fragment>
89 - );
90 - }
91 -}
92 -
93 -export default function EditableProps() {
94 - return (
95 - <div className={styles.App}>
96 - <div className={styles.Header}>Editable props</div>
97 - <ul>
98 - <StatefulClass name="Brian" toggle={true} />
99 - <StatefulFunction name="Brian" />
100 - </ul>
101 - </div>
102 - );
103 -}
104 -
105 -// Below copied from https://usehooks.com/
106 -function useDebounce(value, delay) {
107 - // State and setters for debounced value
108 - const [debouncedValue, setDebouncedValue] = useState(value);
109 -
110 - // Show the value in DevTools
111 - useDebugValue(debouncedValue);
112 -
113 - useEffect(
114 - () => {
115 - // Update debounced value after delay
116 - const handler = setTimeout(() => {
117 - setDebouncedValue(value);
118 - }, delay);
119 -
120 - // Cancel the timeout if value changes (also on delay change or unmount)
121 - // This is how we prevent debounced value from updating if value is changed ...
122 - // .. within the delay period. Timeout gets cleared and restarted.
123 - return () => {
124 - clearTimeout(handler);
125 - };
126 - },
127 - [value, delay] // Only re-call effect if value or delay changes
128 - );
129 -
130 - return debouncedValue;
131 -}
132 -// Above copied from https://usehooks.com/
shells/dev/app/EditableProps/index.js
+128 -2
@@ -1,5 +1,131 @@
1 // @flow
2
3 -import EditableProps from './EditableProps';
3 +import React, {
4 + createContext,
5 + Component,
6 + Fragment,
7 + useCallback,
8 + useDebugValue,
9 + useEffect,
10 + useReducer,
11 + useState,
12 +} from 'react';
13
5 -export default EditableProps;
14 +const initialData = { foo: 'FOO', bar: 'BAR' };
15 +
16 +function reducer(state, action) {
17 + switch (action.type) {
18 + case 'swap':
19 + return { foo: state.bar, bar: state.foo };
20 + default:
21 + throw new Error();
22 + }
23 +}
24 +
25 +type StatefulFunctionProps = {| name: string |};
26 +
27 +function StatefulFunction({ name }: StatefulFunctionProps) {
28 + const [count, updateCount] = useState(0);
29 + const debouncedCount = useDebounce(count, 1000);
30 + const handleUpdateCountClick = useCallback(() => updateCount(count + 1), [
31 + count,
32 + ]);
33 +
34 + const [data, dispatch] = useReducer(reducer, initialData);
35 + const handleUpdateReducerClick = useCallback(
36 + () => dispatch({ type: 'swap' }),
37 + []
38 + );
39 +
40 + return (
41 + <Fragment>
42 + <li>Name: {name}</li>
43 + <li>
44 + <button onClick={handleUpdateCountClick}>
45 + Debounced count: {debouncedCount}
46 + </button>
47 + </li>
48 + <li>
49 + Reducer state: foo "{data.foo}", bar "{data.bar}"
50 + </li>
51 + <li>
52 + <button onClick={handleUpdateReducerClick}>Swap reducer values</button>
53 + </li>
54 + </Fragment>
55 + );
56 +}
57 +
58 +const BoolContext = createContext(true);
59 +BoolContext.displayName = 'BoolContext';
60 +
61 +type Props = {| name: string, toggle: boolean |};
62 +type State = {| cities: Array<string>, state: string |};
63 +
64 +class StatefulClass extends Component<Props, State> {
65 + static contextType = BoolContext;
66 +
67 + state: State = {
68 + cities: ['San Francisco', 'San Jose'],
69 + state: 'California',
70 + };
71 +
72 + handleChange = ({ target }) =>
73 + this.setState({
74 + state: target.value,
75 + });
76 +
77 + render() {
78 + return (
79 + <Fragment>
80 + <li>Name: {this.props.name}</li>
81 + <li>Toggle: {this.props.toggle ? 'true' : 'false'}</li>
82 + <li>
83 + State: <input value={this.state.state} onChange={this.handleChange} />
84 + </li>
85 + <li>Cities: {this.state.cities.join(', ')}</li>
86 + <li>Context: {this.context ? 'true' : 'false'}</li>
87 + </Fragment>
88 + );
89 + }
90 +}
91 +
92 +export default function EditableProps() {
93 + return (
94 + <Fragment>
95 + <h1>Editable props</h1>
96 + <ul>
97 + <StatefulClass name="Brian" toggle={true} />
98 + <StatefulFunction name="Brian" />
99 + </ul>
100 + </Fragment>
101 + );
102 +}
103 +
104 +// Below copied from https://usehooks.com/
105 +function useDebounce(value, delay) {
106 + // State and setters for debounced value
107 + const [debouncedValue, setDebouncedValue] = useState(value);
108 +
109 + // Show the value in DevTools
110 + useDebugValue(debouncedValue);
111 +
112 + useEffect(
113 + () => {
114 + // Update debounced value after delay
115 + const handler = setTimeout(() => {
116 + setDebouncedValue(value);
117 + }, delay);
118 +
119 + // Cancel the timeout if value changes (also on delay change or unmount)
120 + // This is how we prevent debounced value from updating if value is changed ...
121 + // .. within the delay period. Timeout gets cleared and restarted.
122 + return () => {
123 + clearTimeout(handler);
124 + };
125 + },
126 + [value, delay] // Only re-call effect if value or delay changes
127 + );
128 +
129 + return debouncedValue;
130 +}
131 +// Above copied from https://usehooks.com/
shells/dev/app/InspectableElements/InspectableElements.css deleted
-13
@@ -1,13 +0,0 @@
1 -.App {
2 - /* GitHub.com frontend fonts */
3 - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
4 - sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
5 - font-size: 14px;
6 - line-height: 1.5;
7 -}
8 -
9 -.Header {
10 - font-size: 1.5rem;
11 - font-weight: bold;
12 - margin-bottom: 0.5rem;
13 -}
shells/dev/app/InspectableElements/InspectableElements.js
+4 -5
@@ -1,20 +1,19 @@
1 // @flow
2
3 -import React from 'react';
3 +import React, { Fragment } from 'react';
4 import Contexts from './Contexts';
5 import CustomHooks from './CustomHooks';
6 import NestedProps from './NestedProps';
7 -import styles from './InspectableElements.css';
7
8 // TODO Add Immutable JS example
9
10 export default function InspectableElements() {
11 return (
13 - <div className={styles.App}>
14 - <div className={styles.Header}>Inspectable elements</div>
12 + <Fragment>
13 + <h1>Inspectable elements</h1>
14 <NestedProps />
15 <Contexts />
16 <CustomHooks />
18 - </div>
17 + </Fragment>
18 );
19 }
shells/dev/app/ToDoList/List.css
-14
@@ -1,17 +1,3 @@
1 -.App {
2 - /* GitHub.com frontend fonts */
3 - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
4 - sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
5 - font-size: 14px;
6 - line-height: 1.5;
7 -}
8 -
9 -.Header {
10 - font-size: 1.5rem;
11 - font-weight: bold;
12 - margin-bottom: 0.5rem;
13 -}
14 -
1 .Input {
2 font-size: 1rem;
3 padding: 0.25rem;
shells/dev/app/ToDoList/List.js
+4 -4
@@ -1,6 +1,6 @@
1 // @flow
2
3 -import React, { useCallback, useState } from 'react';
3 +import React, { Fragment, useCallback, useState } from 'react';
4 import ListItem from './ListItem';
5 import styles from './List.css';
6
@@ -77,8 +77,8 @@ export default function List(props: Props) {
77 );
78
79 return (
80 - <div className={styles.App}>
81 - <div className={styles.Header}>List</div>
80 + <Fragment>
81 + <h1>List</h1>
82 <input
83 type="text"
84 placeholder="New list item..."
@@ -106,6 +106,6 @@ export default function List(props: Props) {
106 />
107 ))}
108 </ul>
109 - </div>
109 + </Fragment>
110 );
111 }
shells/dev/app/index.js
+4
@@ -4,11 +4,14 @@
4
5 import { createElement } from 'react';
6 import { render, unmountComponentAtNode } from 'react-dom';
7 +import DeeplyNestedComponents from './DeeplyNestedComponents';
8 import EditableProps from './EditableProps';
9 import ElementTypes from './ElementTypes';
10 import InspectableElements from './InspectableElements';
11 import ToDoList from './ToDoList';
12
13 +import './styles.css';
14 +
15 const containers = [];
16
17 function mountHelper(App) {
@@ -26,6 +29,7 @@ function mountTestApp() {
29 mountHelper(InspectableElements);
30 mountHelper(ElementTypes);
31 mountHelper(EditableProps);
32 + mountHelper(DeeplyNestedComponents);
33 }
34
35 function unmountTestApp() {
shells/dev/app/styles.css renamed
+2 -2
@@ -1,4 +1,4 @@
1 -.App {
1 +body {
2 /* GitHub.com frontend fonts */
3 font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
4 sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
@@ -6,7 +6,7 @@
6 line-height: 1.5;
7 }
8
9 -.Header {
9 +h1 {
10 font-size: 1.5rem;
11 font-weight: bold;
12 margin-bottom: 0.5rem;
src/devtools/views/Element.js
+10 -3
@@ -1,6 +1,13 @@
1 // @flow
2
3 -import React, { Fragment, useCallback, useContext, useEffect, useMemo, useRef } from 'react';
3 +import React, {
4 + Fragment,
5 + useCallback,
6 + useContext,
7 + useEffect,
8 + useMemo,
9 + useRef,
10 +} from 'react';
11 import { ElementTypeClass, ElementTypeFunction } from 'src/devtools/types';
12 import { createRegExp } from './utils';
13 import { TreeContext } from './TreeContext';
@@ -26,6 +33,7 @@ export default function ElementView({ index, style }: Props) {
33 const element = getElementAtIndex(index);
34
35 const id = element === null ? null : element.id;
36 + const isSelected = selectedElementID === id;
37
38 const handleDoubleClick = useCallback(() => {
39 if (id !== null) {
@@ -33,7 +41,7 @@ export default function ElementView({ index, style }: Props) {
41 }
42 }, [id, selectOwner]);
43
36 - const ref = useRef();
44 + const ref = useRef<HTMLSpanElement | null>(null);
45
46 useEffect(() => {
47 if (isSelected) {
@@ -64,7 +72,6 @@ export default function ElementView({ index, style }: Props) {
72
73 const { depth, displayName, key, type } = ((element: any): Element);
74
67 - const isSelected = selectedElementID === id;
75 const showDollarR =
76 isSelected && (type === ElementTypeClass || type === ElementTypeFunction);
77