react-native 0.84.0-nightly-20251212-dd390dbbe → 0.84.0-nightly-20251213-07bd24ed0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,7 +29,7 @@ export default class ReactNativeVersion {
29
29
  static major: number = 0;
30
30
  static minor: number = 84;
31
31
  static patch: number = 0;
32
- static prerelease: string | null = 'nightly-20251212-dd390dbbe';
32
+ static prerelease: string | null = 'nightly-20251213-07bd24ed0';
33
33
 
34
34
  static getVersionString(): string {
35
35
  return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
@@ -33,10 +33,10 @@ let isInterceptorEnabled = false;
33
33
 
34
34
  /**
35
35
  * A network interceptor which monkey-patches RCTWebSocketModule methods
36
- * to gather all websocket network requests/responses, in order to show
37
- * their information in the React Native inspector development tool.
36
+ * to gather all websocket network events.
37
+ *
38
+ * @deprecated Since React Native 0.84
38
39
  */
39
-
40
40
  const WebSocketInterceptor = {
41
41
  /**
42
42
  * Invoked when RCTWebSocketModule.close(...) is called.
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(84),
26
26
  RCTVersionPatch: @(0),
27
- RCTVersionPrerelease: @"nightly-20251212-dd390dbbe",
27
+ RCTVersionPrerelease: @"nightly-20251213-07bd24ed0",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.84.0-nightly-20251212-dd390dbbe
1
+ VERSION_NAME=0.84.0-nightly-20251213-07bd24ed0
2
2
  react.internal.publishingGroup=com.facebook.react
3
3
  react.internal.hermesPublishingGroup=com.facebook.hermes
4
4
 
@@ -33,9 +33,6 @@ internal object ChangeBundleLocationDialog {
33
33
  ) {
34
34
  val settings = devSettings.packagerConnectionSettings
35
35
  val currentHost = settings.debugServerHost
36
- settings.debugServerHost = ""
37
- val defaultHost = settings.debugServerHost
38
- settings.debugServerHost = currentHost
39
36
 
40
37
  val layout = LinearLayout(context)
41
38
  layout.orientation = LinearLayout.VERTICAL
@@ -60,11 +57,11 @@ internal object ChangeBundleLocationDialog {
60
57
  input.setTextColor(-0x1000000)
61
58
  input.setText(currentHost)
62
59
 
63
- val defaultHostSuggestion = Button(context)
64
- defaultHostSuggestion.text = defaultHost
65
- defaultHostSuggestion.textSize = 12f
66
- defaultHostSuggestion.isAllCaps = false
67
- defaultHostSuggestion.setOnClickListener { input.setText(defaultHost) }
60
+ val currentHostSuggestion = Button(context)
61
+ currentHostSuggestion.text = currentHost
62
+ currentHostSuggestion.textSize = 12f
63
+ currentHostSuggestion.isAllCaps = false
64
+ currentHostSuggestion.setOnClickListener { input.setText(currentHost) }
68
65
 
69
66
  val networkHost = getDevServerNetworkIpAndPort(context)
70
67
  val networkHostSuggestion = Button(context)
@@ -80,8 +77,12 @@ internal object ChangeBundleLocationDialog {
80
77
  LinearLayout.LayoutParams.MATCH_PARENT,
81
78
  LinearLayout.LayoutParams.WRAP_CONTENT,
82
79
  )
83
- suggestionRow.addView(defaultHostSuggestion)
84
- suggestionRow.addView(networkHostSuggestion)
80
+ suggestionRow.addView(currentHostSuggestion)
81
+
82
+ if (currentHost != networkHost) {
83
+ // We don't want to display two buttons with the same host suggestion.
84
+ suggestionRow.addView(networkHostSuggestion)
85
+ }
85
86
 
86
87
  val instructions = TextView(context)
87
88
  instructions.text =
@@ -15,6 +15,6 @@ public object ReactNativeVersion {
15
15
  "major" to 0,
16
16
  "minor" to 84,
17
17
  "patch" to 0,
18
- "prerelease" to "nightly-20251212-dd390dbbe"
18
+ "prerelease" to "nightly-20251213-07bd24ed0"
19
19
  )
20
20
  }
@@ -22,7 +22,7 @@ constexpr struct {
22
22
  int32_t Major = 0;
23
23
  int32_t Minor = 84;
24
24
  int32_t Patch = 0;
25
- std::string_view Prerelease = "nightly-20251212-dd390dbbe";
25
+ std::string_view Prerelease = "nightly-20251213-07bd24ed0";
26
26
  } ReactNativeVersion;
27
27
 
28
28
  } // namespace facebook::react
@@ -24,11 +24,14 @@ ImageRequest ImageFetcher::requestImage(
24
24
  SurfaceId surfaceId,
25
25
  const ImageRequestParams& imageRequestParams,
26
26
  Tag tag) {
27
- items_[surfaceId].emplace_back(
28
- ImageRequestItem{
29
- .imageSource = imageSource,
30
- .imageRequestParams = imageRequestParams,
31
- .tag = tag});
27
+ {
28
+ std::lock_guard<std::mutex> lock(mutex_);
29
+ items_[surfaceId].emplace_back(
30
+ ImageRequestItem{
31
+ .imageSource = imageSource,
32
+ .imageRequestParams = imageRequestParams,
33
+ .tag = tag});
34
+ }
32
35
 
33
36
  auto telemetry = std::make_shared<ImageTelemetry>(surfaceId);
34
37
 
@@ -40,8 +43,13 @@ ImageRequest ImageFetcher::requestImage(
40
43
  }
41
44
 
42
45
  void ImageFetcher::flushImageRequests() {
43
- if (items_.empty()) {
44
- return;
46
+ std::unordered_map<SurfaceId, std::vector<ImageRequestItem>> items;
47
+ {
48
+ std::lock_guard<std::mutex> lock(mutex_);
49
+ if (items_.empty()) {
50
+ return;
51
+ }
52
+ items.swap(items_);
45
53
  }
46
54
 
47
55
  auto fabricUIManager_ =
@@ -52,14 +60,12 @@ void ImageFetcher::flushImageRequests() {
52
60
  SurfaceId, std::string, JReadableMapBuffer::javaobject)>(
53
61
  "experimental_prefetchResources");
54
62
 
55
- for (auto& [surfaceId, surfaceImageRequests] : items_) {
63
+ for (auto& [surfaceId, surfaceImageRequests] : items) {
56
64
  auto readableMapBuffer = JReadableMapBuffer::createWithContents(
57
65
  serializeImageRequests(surfaceImageRequests));
58
66
  prefetchResources(
59
67
  fabricUIManager_, surfaceId, "RCTImageView", readableMapBuffer.get());
60
68
  }
61
-
62
- items_.clear();
63
69
  }
64
70
 
65
71
  } // namespace facebook::react
@@ -11,6 +11,7 @@
11
11
  #include <react/renderer/imagemanager/ImageRequestParams.h>
12
12
  #include <react/utils/ContextContainer.h>
13
13
  #include <memory>
14
+ #include <mutex>
14
15
  #include <unordered_map>
15
16
  #include <vector>
16
17
 
@@ -38,6 +39,7 @@ class ImageFetcher {
38
39
  Tag tag);
39
40
 
40
41
  std::unordered_map<SurfaceId, std::vector<ImageRequestItem>> items_;
42
+ std::mutex mutex_;
41
43
  std::shared_ptr<const ContextContainer> contextContainer_;
42
44
  };
43
45
  } // namespace facebook::react
@@ -39,7 +39,7 @@ export default function mockComponent<
39
39
 
40
40
  const SuperClass: typeof React.Component<{...}> =
41
41
  typeof RealComponent === 'function' &&
42
- RealComponent.prototype.constructor instanceof React.Component
42
+ RealComponent.prototype?.constructor instanceof React.Component
43
43
  ? RealComponent
44
44
  : React.Component;
45
45
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.84.0-nightly-20251212-dd390dbbe",
3
+ "version": "0.84.0-nightly-20251213-07bd24ed0",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -160,13 +160,13 @@
160
160
  },
161
161
  "dependencies": {
162
162
  "@jest/create-cache-key-function": "^29.7.0",
163
- "@react-native/assets-registry": "0.84.0-nightly-20251212-dd390dbbe",
164
- "@react-native/codegen": "0.84.0-nightly-20251212-dd390dbbe",
165
- "@react-native/community-cli-plugin": "0.84.0-nightly-20251212-dd390dbbe",
166
- "@react-native/gradle-plugin": "0.84.0-nightly-20251212-dd390dbbe",
167
- "@react-native/js-polyfills": "0.84.0-nightly-20251212-dd390dbbe",
168
- "@react-native/normalize-colors": "0.84.0-nightly-20251212-dd390dbbe",
169
- "@react-native/virtualized-lists": "0.84.0-nightly-20251212-dd390dbbe",
163
+ "@react-native/assets-registry": "0.84.0-nightly-20251213-07bd24ed0",
164
+ "@react-native/codegen": "0.84.0-nightly-20251213-07bd24ed0",
165
+ "@react-native/community-cli-plugin": "0.84.0-nightly-20251213-07bd24ed0",
166
+ "@react-native/gradle-plugin": "0.84.0-nightly-20251213-07bd24ed0",
167
+ "@react-native/js-polyfills": "0.84.0-nightly-20251213-07bd24ed0",
168
+ "@react-native/normalize-colors": "0.84.0-nightly-20251213-07bd24ed0",
169
+ "@react-native/virtualized-lists": "0.84.0-nightly-20251213-07bd24ed0",
170
170
  "abort-controller": "^3.0.0",
171
171
  "anser": "^1.4.9",
172
172
  "ansi-regex": "^5.0.0",
@@ -175,7 +175,7 @@
175
175
  "base64-js": "^1.5.1",
176
176
  "commander": "^12.0.0",
177
177
  "flow-enums-runtime": "^0.0.6",
178
- "hermes-compiler": "0.14.0-commitly-202512102158-39fca9fda",
178
+ "hermes-compiler": "0.15.0-commitly-202512121350-fd0e1d3ed",
179
179
  "invariant": "^2.2.4",
180
180
  "jest-environment-node": "^29.7.0",
181
181
  "memoize-one": "^5.0.0",
@@ -1,2 +1,2 @@
1
- HERMES_VERSION_NAME=0.14.0-commitly-202512102158-39fca9fda
1
+ HERMES_VERSION_NAME=0.15.0-commitly-202512121350-fd0e1d3ed
2
2
  HERMES_V1_VERSION_NAME=250829098.0.4
@@ -39,10 +39,6 @@ const InspectorPanel = require('./InspectorPanel').default;
39
39
  const {useState} = React;
40
40
 
41
41
  type PanelPosition = 'top' | 'bottom';
42
- type SelectedTab =
43
- | 'elements-inspector'
44
- | 'network-profiling'
45
- | 'performance-profiling';
46
42
 
47
43
  export type InspectedElementFrame = TouchedViewDataAtPoint['frame'];
48
44
  export type InspectedElement = $ReadOnly<{
@@ -62,8 +58,7 @@ function Inspector({
62
58
  onRequestRerenderApp,
63
59
  reactDevToolsAgent,
64
60
  }: Props): React.Node {
65
- const [selectedTab, setSelectedTab] =
66
- useState<?SelectedTab>('elements-inspector');
61
+ const [inspecting, setInspecting] = useState<boolean>(true);
67
62
 
68
63
  const [panelPosition, setPanelPosition] = useState<PanelPosition>('bottom');
69
64
  const [inspectedElement, setInspectedElement] =
@@ -137,18 +132,8 @@ function Inspector({
137
132
  );
138
133
  };
139
134
 
140
- const setInspecting = (enabled: boolean) => {
141
- setSelectedTab(enabled ? 'elements-inspector' : null);
142
- setInspectedElement(null);
143
- };
144
-
145
- const setPerfing = (enabled: boolean) => {
146
- setSelectedTab(enabled ? 'performance-profiling' : null);
147
- setInspectedElement(null);
148
- };
149
-
150
- const setNetworking = (enabled: boolean) => {
151
- setSelectedTab(enabled ? 'network-profiling' : null);
135
+ const handleSetInspecting = (enabled: boolean) => {
136
+ setInspecting(enabled);
152
137
  setInspectedElement(null);
153
138
  };
154
139
 
@@ -164,7 +149,7 @@ function Inspector({
164
149
 
165
150
  return (
166
151
  <View style={styles.container} pointerEvents="box-none">
167
- {selectedTab === 'elements-inspector' && (
152
+ {inspecting && (
168
153
  <InspectorOverlay
169
154
  inspected={inspectedElement}
170
155
  onTouchPoint={onTouchPoint}
@@ -174,18 +159,14 @@ function Inspector({
174
159
  <SafeAreaView style={[styles.panelContainer, panelContainerStyle]}>
175
160
  <InspectorPanel
176
161
  devtoolsIsOpen={!!reactDevToolsAgent}
177
- inspecting={selectedTab === 'elements-inspector'}
178
- perfing={selectedTab === 'performance-profiling'}
179
- setPerfing={setPerfing}
180
- setInspecting={setInspecting}
162
+ inspecting={inspecting}
163
+ setInspecting={handleSetInspecting}
181
164
  inspected={inspectedElement}
182
165
  hierarchy={elementsHierarchy}
183
166
  selection={selectionIndex}
184
167
  setSelection={setSelection}
185
168
  touchTargeting={PressabilityDebug.isEnabled()}
186
169
  setTouchTargeting={setTouchTargeting}
187
- networking={selectedTab === 'network-profiling'}
188
- setNetworking={setNetworking}
189
170
  />
190
171
  </SafeAreaView>
191
172
  </View>
@@ -23,20 +23,14 @@ const View = require('../../../../../Libraries/Components/View/View').default;
23
23
  const StyleSheet =
24
24
  require('../../../../../Libraries/StyleSheet/StyleSheet').default;
25
25
  const Text = require('../../../../../Libraries/Text/Text').default;
26
- const PerformanceOverlay = require('../perfmonitor/PerformanceOverlay').default;
27
26
  const ElementProperties = require('./ElementProperties').default;
28
- const NetworkOverlay = require('./NetworkOverlay').default;
29
27
 
30
28
  type Props = $ReadOnly<{
31
29
  devtoolsIsOpen: boolean,
32
30
  inspecting: boolean,
33
31
  setInspecting: (val: boolean) => void,
34
- perfing: boolean,
35
- setPerfing: (val: boolean) => void,
36
32
  touchTargeting: boolean,
37
33
  setTouchTargeting: (val: boolean) => void,
38
- networking: boolean,
39
- setNetworking: (val: boolean) => void,
40
34
  hierarchy?: ?ElementsHierarchy,
41
35
  selection?: ?number,
42
36
  setSelection: number => mixed,
@@ -67,10 +61,6 @@ class InspectorPanel extends React.Component<Props> {
67
61
  />
68
62
  </ScrollView>
69
63
  );
70
- } else if (this.props.perfing) {
71
- contents = <PerformanceOverlay />;
72
- } else if (this.props.networking) {
73
- contents = <NetworkOverlay />;
74
64
  } else {
75
65
  contents = <View style={styles.waiting}>{this.renderWaiting()}</View>;
76
66
  }
@@ -83,22 +73,6 @@ class InspectorPanel extends React.Component<Props> {
83
73
  pressed={this.props.inspecting}
84
74
  onClick={this.props.setInspecting}
85
75
  />
86
- {global.RN$Bridgeless === true ? null : (
87
- // These Inspector Panel sub-features are removed under the New Arch.
88
- // See https://github.com/react-native-community/discussions-and-proposals/pull/777
89
- <>
90
- <InspectorPanelButton
91
- title={'Perf'}
92
- pressed={this.props.perfing}
93
- onClick={this.props.setPerfing}
94
- />
95
- <InspectorPanelButton
96
- title={'Network'}
97
- pressed={this.props.networking}
98
- onClick={this.props.setNetworking}
99
- />
100
- </>
101
- )}
102
76
  <InspectorPanelButton
103
77
  title={'Touchables'}
104
78
  pressed={this.props.touchTargeting}
@@ -64,10 +64,11 @@ let isInterceptorEnabled = false;
64
64
 
65
65
  /**
66
66
  * A network interceptor which monkey-patches XMLHttpRequest methods
67
- * to gather all network requests/responses, in order to show their
68
- * information in the React Native inspector development tool.
67
+ * to gather all network requests/responses.
69
68
  * This supports interception with XMLHttpRequest API, including Fetch API
70
69
  * and any other third party libraries that depend on XMLHttpRequest.
70
+ *
71
+ * @deprecated Since React Native 0.84
71
72
  */
72
73
  const XHRInterceptor = {
73
74
  /**
@@ -1,628 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- * @format
9
- */
10
-
11
- 'use strict';
12
-
13
- import type XMLHttpRequest from '../../../../../Libraries/Network/XMLHttpRequest';
14
- import type {ListRenderItemInfo} from '@react-native/virtualized-lists';
15
-
16
- import ScrollView from '../../../../../Libraries/Components/ScrollView/ScrollView';
17
- import * as React from 'react';
18
-
19
- const TouchableHighlight =
20
- require('../../../../../Libraries/Components/Touchable/TouchableHighlight').default;
21
- const View = require('../../../../../Libraries/Components/View/View').default;
22
- const FlatList = require('../../../../../Libraries/Lists/FlatList').default;
23
- const StyleSheet =
24
- require('../../../../../Libraries/StyleSheet/StyleSheet').default;
25
- const Text = require('../../../../../Libraries/Text/Text').default;
26
- const WebSocketInterceptor =
27
- require('../../../../../Libraries/WebSocket/WebSocketInterceptor').default;
28
- const XHRInterceptor = require('./XHRInterceptor').default;
29
-
30
- const LISTVIEW_CELL_HEIGHT = 15;
31
-
32
- // Global id for the intercepted XMLHttpRequest objects.
33
- let nextXHRId = 0;
34
-
35
- type NetworkRequestInfo = {
36
- id: number,
37
- type?: string,
38
- url?: string,
39
- method?: string,
40
- status?: number,
41
- dataSent?: any,
42
- responseContentType?: string,
43
- responseSize?: number,
44
- requestHeaders?: Object,
45
- responseHeaders?: string,
46
- response?: Object | string,
47
- responseURL?: string,
48
- responseType?: string,
49
- timeout?: number,
50
- closeReason?: string,
51
- messages?: string,
52
- serverClose?: Object,
53
- serverError?: Object,
54
- ...
55
- };
56
-
57
- type Props = $ReadOnly<{}>;
58
- type State = {
59
- detailRowId: ?number,
60
- requests: Array<NetworkRequestInfo>,
61
- };
62
-
63
- function getStringByValue(value: any): string {
64
- if (value === undefined) {
65
- return 'undefined';
66
- }
67
- if (typeof value === 'object') {
68
- return JSON.stringify(value);
69
- }
70
- if (typeof value === 'string' && value.length > 500) {
71
- return String(value)
72
- .slice(0, 500)
73
- .concat('\n***TRUNCATED TO 500 CHARACTERS***');
74
- }
75
- return value;
76
- }
77
-
78
- function getTypeShortName(type: any): string {
79
- if (type === 'XMLHttpRequest') {
80
- return 'XHR';
81
- } else if (type === 'WebSocket') {
82
- return 'WS';
83
- }
84
-
85
- return '';
86
- }
87
-
88
- function keyExtractor(request: NetworkRequestInfo): string {
89
- return String(request.id);
90
- }
91
-
92
- const XHR_ID_KEY = Symbol('XHR_ID');
93
-
94
- function getXHRId(xhr: XMLHttpRequest): number {
95
- // $FlowExpectedError[prop-missing]
96
- return xhr[XHR_ID_KEY];
97
- }
98
-
99
- function setXHRId(xhr: XMLHttpRequest, id: number) {
100
- // $FlowExpectedError[prop-missing]
101
- xhr[XHR_ID_KEY] = id;
102
- }
103
-
104
- /**
105
- * Show all the intercepted network requests over the InspectorPanel.
106
- */
107
- class NetworkOverlay extends React.Component<Props, State> {
108
- _requestsListView: ?React.ElementRef<Class<FlatList<NetworkRequestInfo>>>;
109
- _detailScrollView: ?React.ElementRef<typeof ScrollView>;
110
-
111
- // Metrics are used to decide when if the request list should be sticky, and
112
- // scroll to the bottom as new network requests come in, or if the user has
113
- // intentionally scrolled away from the bottom - to instead flash the scroll bar
114
- // and keep the current position
115
- _requestsListViewScrollMetrics: {
116
- contentLength: number,
117
- offset: number,
118
- visibleLength: number,
119
- } = {
120
- offset: 0,
121
- visibleLength: 0,
122
- contentLength: 0,
123
- };
124
-
125
- // Map of `socketId` -> `index in `this.state.requests`.
126
- _socketIdMap: {[number]: number} = {};
127
- // Map of `xhr[XHR_ID_KEY]` -> `index in `this.state.requests`.
128
- _xhrIdMap: {[key: number]: number, ...} = {};
129
-
130
- state: State = {
131
- detailRowId: null,
132
- requests: [],
133
- };
134
-
135
- _enableXHRInterception(): void {
136
- if (XHRInterceptor.isInterceptorEnabled()) {
137
- return;
138
- }
139
- // Show the XHR request item in listView as soon as it was opened.
140
- XHRInterceptor.setOpenCallback((method, url, xhr) => {
141
- // Generate a global id for each intercepted xhr object, add this id
142
- // to the xhr object as a private `_index` property to identify it,
143
- // so that we can distinguish different xhr objects in callbacks.
144
- setXHRId(xhr, nextXHRId++);
145
- const xhrIndex = this.state.requests.length;
146
- this._xhrIdMap[getXHRId(xhr)] = xhrIndex;
147
-
148
- const _xhr: NetworkRequestInfo = {
149
- id: xhrIndex,
150
- type: 'XMLHttpRequest',
151
- method: method,
152
- url: url,
153
- };
154
- this.setState(
155
- {
156
- requests: this.state.requests.concat(_xhr),
157
- },
158
- this._indicateAdditionalRequests,
159
- );
160
- });
161
-
162
- XHRInterceptor.setRequestHeaderCallback((header, value, xhr) => {
163
- // $FlowFixMe[prop-missing]
164
- const xhrIndex = this._getRequestIndexByXHRID(getXHRId(xhr));
165
- if (xhrIndex === -1) {
166
- return;
167
- }
168
-
169
- this.setState(({requests}) => {
170
- const networkRequestInfo = requests[xhrIndex];
171
- if (!networkRequestInfo.requestHeaders) {
172
- networkRequestInfo.requestHeaders = ({}: {[any]: any});
173
- }
174
- networkRequestInfo.requestHeaders[header] = value;
175
- return {requests};
176
- });
177
- });
178
-
179
- XHRInterceptor.setSendCallback((data, xhr) => {
180
- // $FlowFixMe[prop-missing]
181
- const xhrIndex = this._getRequestIndexByXHRID(getXHRId(xhr));
182
- if (xhrIndex === -1) {
183
- return;
184
- }
185
-
186
- this.setState(({requests}) => {
187
- const networkRequestInfo = requests[xhrIndex];
188
- networkRequestInfo.dataSent = data;
189
- return {requests};
190
- });
191
- });
192
-
193
- XHRInterceptor.setHeaderReceivedCallback(
194
- (type, size, responseHeaders, xhr) => {
195
- // $FlowFixMe[prop-missing]
196
- const xhrIndex = this._getRequestIndexByXHRID(getXHRId(xhr));
197
- if (xhrIndex === -1) {
198
- return;
199
- }
200
-
201
- this.setState(({requests}) => {
202
- const networkRequestInfo = requests[xhrIndex];
203
- networkRequestInfo.responseContentType = type;
204
- networkRequestInfo.responseSize = size;
205
- networkRequestInfo.responseHeaders = responseHeaders;
206
- return {requests};
207
- });
208
- },
209
- );
210
-
211
- XHRInterceptor.setResponseCallback(
212
- (status, timeout, response, responseURL, responseType, xhr) => {
213
- // $FlowFixMe[prop-missing]
214
- const xhrIndex = this._getRequestIndexByXHRID(getXHRId(xhr));
215
- if (xhrIndex === -1) {
216
- return;
217
- }
218
-
219
- this.setState(({requests}) => {
220
- const networkRequestInfo = requests[xhrIndex];
221
- networkRequestInfo.status = status;
222
- networkRequestInfo.timeout = timeout;
223
- networkRequestInfo.response = response;
224
- networkRequestInfo.responseURL = responseURL;
225
- networkRequestInfo.responseType = responseType;
226
-
227
- return {requests};
228
- });
229
- },
230
- );
231
-
232
- // Fire above callbacks.
233
- XHRInterceptor.enableInterception();
234
- }
235
-
236
- _enableWebSocketInterception(): void {
237
- if (WebSocketInterceptor.isInterceptorEnabled()) {
238
- return;
239
- }
240
- // Show the WebSocket request item in listView when 'connect' is called.
241
- WebSocketInterceptor.setConnectCallback(
242
- (url, protocols, options, socketId) => {
243
- const socketIndex = this.state.requests.length;
244
- this._socketIdMap[socketId] = socketIndex;
245
- const _webSocket: NetworkRequestInfo = {
246
- id: socketIndex,
247
- type: 'WebSocket',
248
- url: url,
249
- protocols: protocols,
250
- };
251
- this.setState(
252
- {
253
- requests: this.state.requests.concat(_webSocket),
254
- },
255
- this._indicateAdditionalRequests,
256
- );
257
- },
258
- );
259
-
260
- WebSocketInterceptor.setCloseCallback(
261
- (statusCode, closeReason, socketId) => {
262
- const socketIndex = this._socketIdMap[socketId];
263
- if (socketIndex === undefined) {
264
- return;
265
- }
266
- if (statusCode !== null && closeReason !== null) {
267
- this.setState(({requests}) => {
268
- const networkRequestInfo = requests[socketIndex];
269
- networkRequestInfo.status = statusCode;
270
- networkRequestInfo.closeReason = closeReason;
271
- return {requests};
272
- });
273
- }
274
- },
275
- );
276
-
277
- WebSocketInterceptor.setSendCallback((data, socketId) => {
278
- const socketIndex = this._socketIdMap[socketId];
279
- if (socketIndex === undefined) {
280
- return;
281
- }
282
-
283
- this.setState(({requests}) => {
284
- const networkRequestInfo = requests[socketIndex];
285
-
286
- if (!networkRequestInfo.messages) {
287
- networkRequestInfo.messages = '';
288
- }
289
- networkRequestInfo.messages += 'Sent: ' + JSON.stringify(data) + '\n';
290
-
291
- return {requests};
292
- });
293
- });
294
-
295
- WebSocketInterceptor.setOnMessageCallback((message, socketId) => {
296
- const socketIndex = this._socketIdMap[socketId];
297
- if (socketIndex === undefined) {
298
- return;
299
- }
300
-
301
- this.setState(({requests}) => {
302
- const networkRequestInfo = requests[socketIndex];
303
-
304
- if (!networkRequestInfo.messages) {
305
- networkRequestInfo.messages = '';
306
- }
307
- networkRequestInfo.messages +=
308
- 'Received: ' + JSON.stringify(message) + '\n';
309
-
310
- return {requests};
311
- });
312
- });
313
-
314
- WebSocketInterceptor.setOnCloseCallback((message, socketId) => {
315
- const socketIndex = this._socketIdMap[socketId];
316
- if (socketIndex === undefined) {
317
- return;
318
- }
319
-
320
- this.setState(({requests}) => {
321
- const networkRequestInfo = requests[socketIndex];
322
- networkRequestInfo.serverClose = message;
323
-
324
- return {requests};
325
- });
326
- });
327
-
328
- WebSocketInterceptor.setOnErrorCallback((message, socketId) => {
329
- const socketIndex = this._socketIdMap[socketId];
330
- if (socketIndex === undefined) {
331
- return;
332
- }
333
-
334
- this.setState(({requests}) => {
335
- const networkRequestInfo = requests[socketIndex];
336
- networkRequestInfo.serverError = message;
337
-
338
- return {requests};
339
- });
340
- });
341
-
342
- // Fire above callbacks.
343
- WebSocketInterceptor.enableInterception();
344
- }
345
-
346
- componentDidMount() {
347
- this._enableXHRInterception();
348
- this._enableWebSocketInterception();
349
- }
350
-
351
- componentWillUnmount() {
352
- XHRInterceptor.disableInterception();
353
- WebSocketInterceptor.disableInterception();
354
- }
355
-
356
- _renderItem = ({
357
- item,
358
- index,
359
- }: ListRenderItemInfo<NetworkRequestInfo>): React.MixedElement => {
360
- const tableRowViewStyle = [
361
- styles.tableRow,
362
- index % 2 === 1 ? styles.tableRowOdd : styles.tableRowEven,
363
- index === this.state.detailRowId && styles.tableRowPressed,
364
- ];
365
- const urlCellViewStyle = styles.urlCellView;
366
- const methodCellViewStyle = styles.methodCellView;
367
-
368
- return (
369
- <TouchableHighlight
370
- onPress={() => {
371
- this._pressRow(index);
372
- }}>
373
- <View>
374
- <View style={tableRowViewStyle}>
375
- <View style={urlCellViewStyle}>
376
- <Text style={styles.cellText} numberOfLines={1}>
377
- {item.url}
378
- </Text>
379
- </View>
380
- <View style={methodCellViewStyle}>
381
- <Text style={styles.cellText} numberOfLines={1}>
382
- {getTypeShortName(item.type)}
383
- </Text>
384
- </View>
385
- </View>
386
- </View>
387
- </TouchableHighlight>
388
- );
389
- };
390
-
391
- _renderItemDetail(id: number): React.Node {
392
- const requestItem = this.state.requests[id];
393
- const details = Object.keys(requestItem).map(key => {
394
- if (key === 'id') {
395
- return;
396
- }
397
- return (
398
- <View style={styles.detailViewRow} key={key}>
399
- <Text style={[styles.detailViewText, styles.detailKeyCellView]}>
400
- {key}
401
- </Text>
402
- <Text style={[styles.detailViewText, styles.detailValueCellView]}>
403
- {getStringByValue(requestItem[key])}
404
- </Text>
405
- </View>
406
- );
407
- });
408
-
409
- return (
410
- <View>
411
- <TouchableHighlight
412
- style={styles.closeButton}
413
- onPress={this._closeButtonClicked}>
414
- <View>
415
- <Text style={styles.closeButtonText}>v</Text>
416
- </View>
417
- </TouchableHighlight>
418
- <ScrollView
419
- style={styles.detailScrollView}
420
- ref={scrollRef => (this._detailScrollView = scrollRef)}>
421
- {details}
422
- </ScrollView>
423
- </View>
424
- );
425
- }
426
-
427
- _indicateAdditionalRequests = (): void => {
428
- if (this._requestsListView) {
429
- const distanceFromEndThreshold = LISTVIEW_CELL_HEIGHT * 2;
430
- const {offset, visibleLength, contentLength} =
431
- this._requestsListViewScrollMetrics;
432
- const distanceFromEnd = contentLength - visibleLength - offset;
433
- const isCloseToEnd = distanceFromEnd <= distanceFromEndThreshold;
434
- if (isCloseToEnd) {
435
- this._requestsListView.scrollToEnd();
436
- } else {
437
- this._requestsListView.flashScrollIndicators();
438
- }
439
- }
440
- };
441
-
442
- _captureRequestsListView = (listRef: ?FlatList<NetworkRequestInfo>): void => {
443
- this._requestsListView = listRef;
444
- };
445
-
446
- _requestsListViewOnScroll = (e: Object): void => {
447
- this._requestsListViewScrollMetrics.offset = e.nativeEvent.contentOffset.y;
448
- this._requestsListViewScrollMetrics.visibleLength =
449
- e.nativeEvent.layoutMeasurement.height;
450
- this._requestsListViewScrollMetrics.contentLength =
451
- e.nativeEvent.contentSize.height;
452
- };
453
-
454
- /**
455
- * Popup a scrollView to dynamically show detailed information of
456
- * the request, when pressing a row in the network flow listView.
457
- */
458
- _pressRow(rowId: number): void {
459
- this.setState({detailRowId: rowId}, this._scrollDetailToTop);
460
- }
461
-
462
- _scrollDetailToTop = (): void => {
463
- if (this._detailScrollView) {
464
- this._detailScrollView.scrollTo({
465
- y: 0,
466
- animated: false,
467
- });
468
- }
469
- };
470
-
471
- _closeButtonClicked = () => {
472
- this.setState({detailRowId: null});
473
- };
474
-
475
- _getRequestIndexByXHRID(index: number): number {
476
- if (index === undefined) {
477
- return -1;
478
- }
479
- const xhrIndex = this._xhrIdMap[index];
480
- if (xhrIndex === undefined) {
481
- return -1;
482
- } else {
483
- return xhrIndex;
484
- }
485
- }
486
-
487
- render(): React.Node {
488
- const {requests, detailRowId} = this.state;
489
-
490
- return (
491
- <View style={styles.container}>
492
- {detailRowId != null && this._renderItemDetail(detailRowId)}
493
- <View style={styles.listViewTitle}>
494
- {requests.length > 0 && (
495
- <View style={styles.tableRow}>
496
- <View style={styles.urlTitleCellView}>
497
- <Text style={styles.cellText} numberOfLines={1}>
498
- URL
499
- </Text>
500
- </View>
501
- <View style={styles.methodTitleCellView}>
502
- <Text style={styles.cellText} numberOfLines={1}>
503
- Type
504
- </Text>
505
- </View>
506
- </View>
507
- )}
508
- </View>
509
-
510
- <FlatList
511
- ref={this._captureRequestsListView}
512
- onScroll={this._requestsListViewOnScroll}
513
- style={styles.listView}
514
- data={requests}
515
- renderItem={this._renderItem}
516
- keyExtractor={keyExtractor}
517
- extraData={this.state}
518
- />
519
- </View>
520
- );
521
- }
522
- }
523
-
524
- const styles = StyleSheet.create({
525
- container: {
526
- paddingTop: 10,
527
- paddingBottom: 10,
528
- paddingLeft: 5,
529
- paddingRight: 5,
530
- },
531
- listViewTitle: {
532
- height: 20,
533
- },
534
- listView: {
535
- flex: 1,
536
- height: 60,
537
- },
538
- tableRow: {
539
- flexDirection: 'row',
540
- flex: 1,
541
- height: LISTVIEW_CELL_HEIGHT,
542
- },
543
- tableRowEven: {
544
- backgroundColor: '#555',
545
- },
546
- tableRowOdd: {
547
- backgroundColor: '#000',
548
- },
549
- tableRowPressed: {
550
- backgroundColor: '#3B5998',
551
- },
552
- cellText: {
553
- color: 'white',
554
- fontSize: 12,
555
- },
556
- methodTitleCellView: {
557
- height: 18,
558
- borderColor: '#DCD7CD',
559
- borderTopWidth: 1,
560
- borderBottomWidth: 1,
561
- borderRightWidth: 1,
562
- alignItems: 'center',
563
- justifyContent: 'center',
564
- backgroundColor: '#444',
565
- flex: 1,
566
- },
567
- urlTitleCellView: {
568
- height: 18,
569
- borderColor: '#DCD7CD',
570
- borderTopWidth: 1,
571
- borderBottomWidth: 1,
572
- borderLeftWidth: 1,
573
- borderRightWidth: 1,
574
- justifyContent: 'center',
575
- backgroundColor: '#444',
576
- flex: 5,
577
- paddingLeft: 3,
578
- },
579
- methodCellView: {
580
- height: 15,
581
- borderColor: '#DCD7CD',
582
- borderRightWidth: 1,
583
- alignItems: 'center',
584
- justifyContent: 'center',
585
- flex: 1,
586
- },
587
- urlCellView: {
588
- height: 15,
589
- borderColor: '#DCD7CD',
590
- borderLeftWidth: 1,
591
- borderRightWidth: 1,
592
- justifyContent: 'center',
593
- flex: 5,
594
- paddingLeft: 3,
595
- },
596
- detailScrollView: {
597
- flex: 1,
598
- height: 180,
599
- marginTop: 5,
600
- marginBottom: 5,
601
- },
602
- detailKeyCellView: {
603
- flex: 1.3,
604
- },
605
- detailValueCellView: {
606
- flex: 2,
607
- },
608
- detailViewRow: {
609
- flexDirection: 'row',
610
- paddingHorizontal: 3,
611
- },
612
- detailViewText: {
613
- color: 'white',
614
- fontSize: 11,
615
- },
616
- closeButtonText: {
617
- color: 'white',
618
- fontSize: 10,
619
- },
620
- closeButton: {
621
- marginTop: 5,
622
- backgroundColor: '#888',
623
- justifyContent: 'center',
624
- alignItems: 'center',
625
- },
626
- });
627
-
628
- export default NetworkOverlay;
@@ -1,66 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- * @format
9
- */
10
-
11
- 'use strict';
12
-
13
- import * as React from 'react';
14
-
15
- const View = require('../../../../../Libraries/Components/View/View').default;
16
- const StyleSheet =
17
- require('../../../../../Libraries/StyleSheet/StyleSheet').default;
18
- const Text = require('../../../../../Libraries/Text/Text').default;
19
- const PerformanceLogger =
20
- require('../../../../../Libraries/Utilities/GlobalPerformanceLogger').default;
21
-
22
- class PerformanceOverlay extends React.Component<{...}> {
23
- render(): React.Node {
24
- const perfLogs = PerformanceLogger.getTimespans();
25
- const items = [];
26
-
27
- for (const key in perfLogs) {
28
- if (perfLogs[key]?.totalTime) {
29
- const unit = key === 'BundleSize' ? 'b' : 'ms';
30
- items.push(
31
- <View style={styles.row} key={key}>
32
- <Text style={[styles.text, styles.label]}>{key}</Text>
33
- <Text style={[styles.text, styles.totalTime]}>
34
- {perfLogs[key].totalTime + unit}
35
- </Text>
36
- </View>,
37
- );
38
- }
39
- }
40
-
41
- return <View style={styles.container}>{items}</View>;
42
- }
43
- }
44
-
45
- const styles = StyleSheet.create({
46
- container: {
47
- height: 100,
48
- paddingTop: 10,
49
- },
50
- label: {
51
- flex: 1,
52
- },
53
- row: {
54
- flexDirection: 'row',
55
- paddingHorizontal: 10,
56
- },
57
- text: {
58
- color: 'white',
59
- fontSize: 12,
60
- },
61
- totalTime: {
62
- paddingRight: 100,
63
- },
64
- });
65
-
66
- export default PerformanceOverlay;