Skip to content

Commit

Permalink
Merge branch 'main' into fix-suspense-throttling
Browse files Browse the repository at this point in the history
  • Loading branch information
sunderls committed Apr 9, 2022
2 parents b1062aa + e0160d5 commit d76e2e4
Show file tree
Hide file tree
Showing 54 changed files with 3,523 additions and 1,816 deletions.
8 changes: 4 additions & 4 deletions README.md
Expand Up @@ -40,14 +40,14 @@ You can improve it by sending pull requests to [this repository](https://github.
We have several examples [on the website](https://reactjs.org/). Here is the first one to get you started:

```jsx
import { createRoot } from 'react-dom/client';

function HelloMessage({ name }) {
return <div>Hello {name}</div>;
}

ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById('container')
);
const root = createRoot(document.getElementById('container'));
root.render(<HelloMessage name="Taylor" />);
```

This example will render "Hello Taylor" into a container on the page.
Expand Down
18 changes: 9 additions & 9 deletions fixtures/attribute-behavior/AttributeTableSnapshot.md
Expand Up @@ -9787,14 +9787,14 @@
| `src=(integer)`| (changed)| `"http://localhost:3000/1"` |
| `src=(NaN)`| (changed, warning)| `"http://localhost:3000/NaN"` |
| `src=(float)`| (changed)| `"http://localhost:3000/99.99"` |
| `src=(true)`| (initial, warning)| `<empty string>` |
| `src=(true)`| (changed, warning, ssr mismatch)| `"http://localhost:3000/true"` |
| `src=(false)`| (initial, warning)| `<empty string>` |
| `src=(string 'true')`| (changed)| `"http://localhost:3000/true"` |
| `src=(string 'false')`| (changed)| `"http://localhost:3000/false"` |
| `src=(string 'on')`| (changed)| `"http://localhost:3000/on"` |
| `src=(string 'off')`| (changed)| `"http://localhost:3000/off"` |
| `src=(symbol)`| (initial, warning)| `<empty string>` |
| `src=(function)`| (initial, warning)| `<empty string>` |
| `src=(symbol)`| (changed, error, warning, ssr mismatch)| `` |
| `src=(function)`| (changed, warning, ssr mismatch)| `"http://localhost:3000/function%20f()%20%7B%7D"` |
| `src=(null)`| (initial)| `<empty string>` |
| `src=(undefined)`| (initial)| `<empty string>` |

Expand Down Expand Up @@ -11980,21 +11980,21 @@
| `value=(empty string)`| (initial)| `<empty string>` |
| `value=(array with string)`| (changed)| `"string"` |
| `value=(empty array)`| (initial)| `<empty string>` |
| `value=(object)`| (changed, ssr error, ssr mismatch)| `"result of toString()"` |
| `value=(object)`| (changed)| `"result of toString()"` |
| `value=(numeric string)`| (changed)| `"42"` |
| `value=(-1)`| (changed)| `"-1"` |
| `value=(0)`| (changed)| `"0"` |
| `value=(integer)`| (changed)| `"1"` |
| `value=(NaN)`| (changed, warning)| `"NaN"` |
| `value=(float)`| (changed)| `"99.99"` |
| `value=(true)`| (changed, ssr mismatch)| `"true"` |
| `value=(false)`| (changed, ssr mismatch)| `"false"` |
| `value=(true)`| (changed)| `"true"` |
| `value=(false)`| (changed)| `"false"` |
| `value=(string 'true')`| (changed)| `"true"` |
| `value=(string 'false')`| (changed)| `"false"` |
| `value=(string 'on')`| (changed)| `"on"` |
| `value=(string 'off')`| (changed)| `"off"` |
| `value=(symbol)`| (initial, warning)| `<empty string>` |
| `value=(function)`| (initial, warning)| `<empty string>` |
| `value=(symbol)`| (initial, warning, ssr error, ssr mismatch)| `<empty string>` |
| `value=(function)`| (initial, warning, ssr mismatch)| `<empty string>` |
| `value=(null)`| (initial, warning)| `<empty string>` |
| `value=(undefined)`| (initial)| `<empty string>` |

Expand All @@ -12018,7 +12018,7 @@
| `value=(string 'false')`| (changed)| `"false"` |
| `value=(string 'on')`| (changed)| `"on"` |
| `value=(string 'off')`| (changed)| `"off"` |
| `value=(symbol)`| (initial, warning, ssr error, ssr mismatch)| `<empty string>` |
| `value=(symbol)`| (initial, warning)| `<empty string>` |
| `value=(function)`| (initial, warning)| `<empty string>` |
| `value=(null)`| (initial)| `<empty string>` |
| `value=(undefined)`| (initial)| `<empty string>` |
Expand Down
29 changes: 2 additions & 27 deletions packages/create-subscription/README.md
@@ -1,33 +1,8 @@
# create-subscription

`create-subscription` is a utility for subscribing to external data sources inside React components. It is officially supported and maintained by the React team.
`create-subscription` is a utility for subscribing to external data sources inside React components.

## When should you NOT use this?

This utility should be used for subscriptions to a single value that are typically only read in one place and may update frequently (e.g. a component that subscribes to a geolocation API to show a dot on a map).

Other cases have **better long-term solutions**:
* Redux/Flux stores should use the [context API](https://reactjs.org/docs/context.html) instead.
* I/O subscriptions (e.g. notifications) that update infrequently should use [`react-cache`](https://github.com/facebook/react/blob/main/packages/react-cache/README.md) instead.
* Complex libraries like Relay/Apollo should manage subscriptions manually with the same techniques which this library uses under the hood (as referenced [here](https://gist.github.com/bvaughn/d569177d70b50b58bff69c3c4a5353f3)) in a way that is most optimized for their library usage.

## Limitations in async mode

The main motivation for `create-subscription` is to provide a way for library authors to ensure compatibility with React's upcoming asynchronous rendering mode. `create-subscription` guarantees correctness in async mode, accounting for the subtle bugs and edge cases that a library author might otherwise miss.

However, [it achieves correctness by sometimes de-opting to synchronous mode](https://github.com/facebook/react/issues/13186#issuecomment-403959161), obviating the benefits of async rendering. This is an inherent limitation of storing state outside of React's managed state queue and rendering in response to a change event.

The effect of de-opting to sync mode is that the main thread may periodically be blocked (in the case of CPU-bound work), and placeholders may appear earlier than desired (in the case of IO-bound work).

For **full compatibility** with asynchronous rendering, including both **time-slicing** and **React Suspense**, the suggested longer-term solution is to move to one of the patterns described in the previous section.

## What types of subscriptions can this support?

This abstraction can handle a variety of subscription types, including:
* Event dispatchers like `HTMLInputElement`.
* Custom pub/sub components like Relay's `FragmentSpecResolver`.
* Observable types like RxJS `BehaviorSubject` and `ReplaySubject`. (Types like RxJS `Subject` or `Observable` are not supported, because they provide no way to read the "current" value after it has been emitted.)
* Native Promises.
**It is no longer maintained and will not be updated. Use the built-in [`React.useSyncExternalStore`](https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore) instead.**

# Installation

Expand Down
Expand Up @@ -325,6 +325,75 @@ const tests = {
useHook();
}
`,
`
// Valid because the neither the conditions before or after the hook affect the hook call
// Failed prior to implementing BigInt because pathsFromStartToEnd and allPathsFromStartToEnd were too big and had rounding errors
const useSomeHook = () => {};
const SomeName = () => {
const filler = FILLER ?? FILLER ?? FILLER;
const filler2 = FILLER ?? FILLER ?? FILLER;
const filler3 = FILLER ?? FILLER ?? FILLER;
const filler4 = FILLER ?? FILLER ?? FILLER;
const filler5 = FILLER ?? FILLER ?? FILLER;
const filler6 = FILLER ?? FILLER ?? FILLER;
const filler7 = FILLER ?? FILLER ?? FILLER;
const filler8 = FILLER ?? FILLER ?? FILLER;
useSomeHook();
if (anyConditionCanEvenBeFalse) {
return null;
}
return (
<React.Fragment>
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
{FILLER ? FILLER : FILLER}
</React.Fragment>
);
};
`,
`
// Valid because the neither the condition nor the loop affect the hook call.
function App(props) {
Expand Down
19 changes: 10 additions & 9 deletions packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
Expand Up @@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

/* global BigInt */
/* eslint-disable no-for-of-loops/no-for-of-loops */

'use strict';
Expand Down Expand Up @@ -175,7 +176,7 @@ export default {
cyclic.add(cyclicSegment);
}

return 0;
return BigInt('0');
}

// add the current segment to pathList
Expand All @@ -187,19 +188,19 @@ export default {
}

if (codePath.thrownSegments.includes(segment)) {
paths = 0;
paths = BigInt('0');
} else if (segment.prevSegments.length === 0) {
paths = 1;
paths = BigInt('1');
} else {
paths = 0;
paths = BigInt('0');
for (const prevSegment of segment.prevSegments) {
paths += countPathsFromStart(prevSegment, pathList);
}
}

// If our segment is reachable then there should be at least one path
// to it from the start of our code path.
if (segment.reachable && paths === 0) {
if (segment.reachable && paths === BigInt('0')) {
cache.delete(segment.id);
} else {
cache.set(segment.id, paths);
Expand Down Expand Up @@ -246,7 +247,7 @@ export default {
cyclic.add(cyclicSegment);
}

return 0;
return BigInt('0');
}

// add the current segment to pathList
Expand All @@ -258,11 +259,11 @@ export default {
}

if (codePath.thrownSegments.includes(segment)) {
paths = 0;
paths = BigInt('0');
} else if (segment.nextSegments.length === 0) {
paths = 1;
paths = BigInt('1');
} else {
paths = 0;
paths = BigInt('0');
for (const nextSegment of segment.nextSegments) {
paths += countPathsToEnd(nextSegment, pathList);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-core/package.json
@@ -1,6 +1,6 @@
{
"name": "react-devtools-core",
"version": "4.24.3",
"version": "4.24.4",
"description": "Use react-devtools outside of the browser",
"license": "MIT",
"main": "./dist/backend.js",
Expand Down
4 changes: 2 additions & 2 deletions packages/react-devtools-extensions/chrome/manifest.json
Expand Up @@ -2,8 +2,8 @@
"manifest_version": 2,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Chrome Developer Tools.",
"version": "4.24.3",
"version_name": "4.24.3",
"version": "4.24.4",
"version_name": "4.24.4",
"minimum_chrome_version": "60",
"icons": {
"16": "icons/16-production.png",
Expand Down
4 changes: 2 additions & 2 deletions packages/react-devtools-extensions/edge/manifest.json
Expand Up @@ -2,8 +2,8 @@
"manifest_version": 2,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Microsoft Edge Developer Tools.",
"version": "4.24.3",
"version_name": "4.24.3",
"version": "4.24.4",
"version_name": "4.24.4",
"minimum_chrome_version": "60",
"icons": {
"16": "icons/16-production.png",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-extensions/firefox/manifest.json
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Firefox Developer Tools.",
"version": "4.24.3",
"version": "4.24.4",
"applications": {
"gecko": {
"id": "@react-devtools",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-inline/package.json
@@ -1,6 +1,6 @@
{
"name": "react-devtools-inline",
"version": "4.24.3",
"version": "4.24.4",
"description": "Embed react-devtools within a website",
"license": "MIT",
"main": "./dist/backend.js",
Expand Down
5 changes: 4 additions & 1 deletion packages/react-devtools-inline/src/frontend.js
Expand Up @@ -18,15 +18,18 @@ import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
import type {Props} from 'react-devtools-shared/src/devtools/views/DevTools';

type Config = {|
checkBridgeProtocolCompatibility?: boolean,
supportsNativeInspection?: boolean,
supportsProfiling?: boolean,
|};

export function createStore(bridge: FrontendBridge, config?: Config): Store {
return new Store(bridge, {
checkBridgeProtocolCompatibility: true,
supportsTraceUpdates: true,
supportsTimeline: true,
supportsNativeInspection: config?.supportsNativeInspection !== false,
supportsNativeInspection: true,
...config,
});
}

Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-timeline/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "react-devtools-timeline",
"version": "4.24.3",
"version": "4.24.4",
"license": "MIT",
"dependencies": {
"@elg/speedscope": "1.9.0-a6f84db",
Expand Down
8 changes: 8 additions & 0 deletions packages/react-devtools/CHANGELOG.md
Expand Up @@ -4,6 +4,14 @@

---

### 4.24.4
April 8, 2022

* Allow react-devtools-inline `createStore()` method to override Store config params ([bvaughn](https://github.com/bvaughn) in [#24303](https://github.com/facebook/react/pull/24303))
* [ReactDebugTools] wrap uncaught error from rendering user's component ([mondaychen](https://github.com/mondaychen) in [#24216](https://github.com/facebook/react/pull/24216))

---

### 4.24.3
March 29, 2022

Expand Down
4 changes: 2 additions & 2 deletions packages/react-devtools/package.json
@@ -1,6 +1,6 @@
{
"name": "react-devtools",
"version": "4.24.3",
"version": "4.24.4",
"description": "Use react-devtools outside of the browser",
"license": "MIT",
"repository": {
Expand All @@ -26,7 +26,7 @@
"electron": "^11.1.0",
"ip": "^1.1.4",
"minimist": "^1.2.3",
"react-devtools-core": "4.24.3",
"react-devtools-core": "4.24.4",
"update-notifier": "^2.1.0"
}
}

0 comments on commit d76e2e4

Please sign in to comment.