10
10
import type { ReactContext } from 'shared/ReactTypes' ;
11
11
12
12
import * as React from 'react' ;
13
- import {
14
- createContext ,
15
- useCallback ,
16
- useContext ,
17
- useEffect ,
18
- useMemo ,
19
- useState ,
20
- } from 'react' ;
21
- import { createResource } from 'react-devtools-shared/src/devtools/cache' ;
13
+ import { createContext , useContext , useEffect , useState } from 'react' ;
22
14
import {
23
15
BridgeContext ,
24
16
StoreContext ,
25
17
} from 'react-devtools-shared/src/devtools/views/context' ;
26
- import { TreeStateContext } from '.. /TreeContext' ;
18
+ import { TreeStateContext } from 'react-devtools-shared/src/devtools/views/Components /TreeContext' ;
27
19
28
- import type { StateContext } from '.. /TreeContext' ;
20
+ import type { StateContext } from 'react-devtools-shared/src/devtools/views/Components /TreeContext' ;
29
21
import type { FrontendBridge } from 'react-devtools-shared/src/bridge' ;
30
22
import type Store from 'react-devtools-shared/src/devtools/store' ;
31
23
import type { StyleAndLayout as StyleAndLayoutBackend } from 'react-devtools-shared/src/backend/NativeStyleEditor/types' ;
32
24
import type { StyleAndLayout as StyleAndLayoutFrontend } from './types' ;
33
- import type { Element } from 'react-devtools-shared/src/frontend/types' ;
34
- import type {
35
- Resource ,
36
- Thenable ,
37
- } from 'react-devtools-shared/src/devtools/cache' ;
38
-
39
- export type GetStyleAndLayout = ( id : number ) => StyleAndLayoutFrontend | null ;
40
25
41
- type Context = {
42
- getStyleAndLayout : GetStyleAndLayout ,
43
- } ;
26
+ type Context = StyleAndLayoutFrontend | null ;
44
27
45
28
const NativeStyleContext : ReactContext < Context > = createContext< Context > (
46
29
((null: any): Context),
47
30
);
48
31
NativeStyleContext.displayName = 'NativeStyleContext';
49
32
50
- type ResolveFn = (styleAndLayout: StyleAndLayoutFrontend) => void ;
51
- type InProgressRequest = {
52
- promise : Thenable < StyleAndLayoutFrontend > ,
53
- resolveFn : ResolveFn ,
54
- } ;
55
-
56
- const inProgressRequests : WeakMap < Element , InProgressRequest > = new WeakMap ( ) ;
57
- const resource : Resource < Element , Element , StyleAndLayoutFrontend > =
58
- createResource (
59
- ( element : Element ) => {
60
- const request = inProgressRequests . get ( element ) ;
61
- if ( request != null ) {
62
- return request . promise ;
63
- }
64
-
65
- let resolveFn :
66
- | ResolveFn
67
- | ( (
68
- result : Promise < StyleAndLayoutFrontend > | StyleAndLayoutFrontend ,
69
- ) => void ) = ( ( null : any ) : ResolveFn ) ;
70
- const promise = new Promise ( resolve => {
71
- resolveFn = resolve ;
72
- } ) ;
73
-
74
- inProgressRequests . set ( element , ( { promise, resolveFn} : $FlowFixMe ) ) ;
75
-
76
- return ( promise : $FlowFixMe ) ;
77
- } ,
78
- ( element : Element ) => element ,
79
- { useWeakMap : true } ,
80
- ) ;
81
-
82
33
type Props = {
83
34
children : React$Node ,
84
35
} ;
85
36
86
37
function NativeStyleContextController({ children } : Props): React.Node {
87
38
const bridge = useContext < FrontendBridge > ( BridgeContext ) ;
88
39
const store = useContext < Store > ( StoreContext ) ;
89
-
90
- const getStyleAndLayout = useCallback < GetStyleAndLayout > (
91
- ( id : number ) => {
92
- const element = store . getElementByID ( id ) ;
93
- if ( element !== null ) {
94
- return resource . read ( element ) ;
95
- } else {
96
- return null ;
97
- }
98
- } ,
99
- [ store ] ,
100
- ) ;
101
-
102
- // It's very important that this context consumes inspectedElementID and not NativeStyleID.
103
- // Otherwise the effect that sends the "inspect" message across the bridge-
104
- // would itself be blocked by the same render that suspends (waiting for the data).
105
40
const { inspectedElementID} = useContext < StateContext > ( TreeStateContext ) ;
106
41
107
42
const [ currentStyleAndLayout , setCurrentStyleAndLayout ] =
108
43
useState < StyleAndLayoutFrontend | null > ( null ) ;
109
44
110
- // This effect handler invalidates the suspense cache and schedules rendering updates with React.
111
- useEffect ( ( ) => {
112
- const onStyleAndLayout = ( { id, layout, style} : StyleAndLayoutBackend ) => {
113
- const element = store . getElementByID ( id ) ;
114
- if ( element !== null ) {
115
- const styleAndLayout : StyleAndLayoutFrontend = {
116
- layout,
117
- style,
118
- } ;
119
- const request = inProgressRequests . get ( element ) ;
120
- if ( request != null ) {
121
- inProgressRequests . delete ( element ) ;
122
- request . resolveFn ( styleAndLayout ) ;
123
- setCurrentStyleAndLayout ( styleAndLayout ) ;
124
- } else {
125
- resource . write ( element , styleAndLayout ) ;
126
-
127
- // Schedule update with React if the currently-selected element has been invalidated.
128
- if ( id === inspectedElementID ) {
129
- setCurrentStyleAndLayout ( styleAndLayout ) ;
130
- }
131
- }
132
- }
133
- } ;
134
-
135
- bridge . addListener ( 'NativeStyleEditor_styleAndLayout' , onStyleAndLayout ) ;
136
- return ( ) =>
137
- bridge . removeListener (
138
- 'NativeStyleEditor_styleAndLayout' ,
139
- onStyleAndLayout ,
140
- ) ;
141
- } , [ bridge , currentStyleAndLayout , inspectedElementID , store ] ) ;
142
-
143
45
// This effect handler polls for updates on the currently selected element.
144
46
useEffect ( ( ) => {
145
47
if ( inspectedElementID === null ) {
48
+ setCurrentStyleAndLayout ( null ) ;
146
49
return ( ) => { } ;
147
50
}
148
51
149
- const rendererID = store . getRendererIDForElement ( inspectedElementID ) ;
150
-
151
- let timeoutID : TimeoutID | null = null ;
152
-
52
+ let requestTimeoutId : TimeoutID | null = null ;
153
53
const sendRequest = ( ) => {
154
- timeoutID = null ;
54
+ requestTimeoutId = null ;
55
+ const rendererID = store . getRendererIDForElement ( inspectedElementID ) ;
155
56
156
57
if ( rendererID !== null ) {
157
58
bridge . send ( 'NativeStyleEditor_measure' , {
@@ -165,38 +66,37 @@ function NativeStyleContextController({children}: Props): React.Node {
165
66
// We'll poll for an update in the response handler below.
166
67
sendRequest ( ) ;
167
68
168
- const onStyleAndLayout = ( { id} : StyleAndLayoutBackend ) => {
69
+ const onStyleAndLayout = ( { id, layout , style } : StyleAndLayoutBackend ) => {
169
70
// If this is the element we requested, wait a little bit and then ask for another update.
170
71
if ( id === inspectedElementID ) {
171
- if ( timeoutID !== null ) {
172
- clearTimeout ( timeoutID ) ;
72
+ if ( requestTimeoutId !== null ) {
73
+ clearTimeout ( requestTimeoutId ) ;
173
74
}
174
- timeoutID = setTimeout ( sendRequest , 1000 ) ;
75
+ requestTimeoutId = setTimeout ( sendRequest , 1000 ) ;
175
76
}
77
+
78
+ const styleAndLayout : StyleAndLayoutFrontend = {
79
+ layout,
80
+ style,
81
+ } ;
82
+ setCurrentStyleAndLayout ( styleAndLayout ) ;
176
83
} ;
177
84
178
85
bridge . addListener ( 'NativeStyleEditor_styleAndLayout' , onStyleAndLayout ) ;
179
-
180
86
return ( ) => {
181
87
bridge . removeListener (
182
88
'NativeStyleEditor_styleAndLayout' ,
183
89
onStyleAndLayout ,
184
90
) ;
185
91
186
- if ( timeoutID !== null ) {
187
- clearTimeout ( timeoutID ) ;
92
+ if ( requestTimeoutId !== null ) {
93
+ clearTimeout ( requestTimeoutId ) ;
188
94
}
189
95
} ;
190
96
} , [ bridge , inspectedElementID , store ] ) ;
191
97
192
- const value = useMemo (
193
- ( ) => ( { getStyleAndLayout} ) ,
194
- // NativeStyle is used to invalidate the cache and schedule an update with React.
195
- [ currentStyleAndLayout , getStyleAndLayout ] ,
196
- ) ;
197
-
198
98
return (
199
- < NativeStyleContext . Provider value = { value } >
99
+ < NativeStyleContext . Provider value = { currentStyleAndLayout } >
200
100
{ children }
201
101
</ NativeStyleContext . Provider >
202
102
) ;
0 commit comments