Skip to content

Commit

Permalink
replace use-subscription with use-sync-external-store (#36733)
Browse files Browse the repository at this point in the history
- [x] Make sure the linting passes by running `yarn lint`

Back in 2019, React released the first version of `use-subscription` (facebook/react#15022). At the time, we only has limited information about concurrent rendering, and #9026 add the initial concurrent mode support.

In 2020, React provides a first-party official API `useMutableSource` (reactjs/rfcs#147, facebook/react#18000):

> ... enables React components to safely and efficiently read from a mutable external source in Concurrent Mode.

React 18 introduces `useMutableSource`'s replacement `useSyncExternalStore` (see details here: reactwg/react-18#86), and React changes `use-subscription` implementation to use `useSyncExternalStore` directly: facebook/react#24289

> In React 18, `React.useSyncExternalStore` is a built-in replacement for `useSubscription`.
> 
> This PR makes `useSubscription` simply use `React.useSyncExternalStore` when available. For pre-18, it uses a `use-sync-external-store` shim which is very similar in `use-subscription` but fixes some flaws with concurrent rendering.

And according to `use-subscription`:

> You may now migrate to [`use-sync-external-store`](https://www.npmjs.com/package/use-sync-external-store) directly instead, which has the same API as `React.useSyncExternalStore`. The `use-subscription` package is now a thin wrapper over `use-sync-external-store` and will not be updated further.

The PR does exactly that:

- Removes the precompiled `use-subscription` introduced in #35746
- Adds the `use-sync-external-store` to the dependencies.
  - The `use-sync-external-store` package enables compatibility with React 16 and React 17.
  - Do not pre-compile `use-sync-external-store` since it is also the dependency of some popular React state management libraries like `react-redux`, `zustand`, `valtio`, `@xstate/react` and `@apollo/client`, etc. By install
- Replace `useSubscription` usage with `useSyncExternalStore` 

---

Ref: #9026, #35746 and #36159


Co-authored-by: Jiachi Liu <4800338+huozhi@users.noreply.github.com>
  • Loading branch information
SukkaW and huozhi committed May 8, 2022
1 parent 3fd1168 commit 26459ef
Show file tree
Hide file tree
Showing 7 changed files with 15 additions and 76 deletions.
21 changes: 0 additions & 21 deletions packages/next/compiled/use-subscription/LICENSE

This file was deleted.

25 changes: 0 additions & 25 deletions packages/next/compiled/use-subscription/index.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/next/compiled/use-subscription/package.json

This file was deleted.

4 changes: 2 additions & 2 deletions packages/next/package.json
Expand Up @@ -72,7 +72,8 @@
"@next/env": "12.1.7-canary.3",
"caniuse-lite": "^1.0.30001332",
"postcss": "8.4.5",
"styled-jsx": "5.0.2"
"styled-jsx": "5.0.2",
"use-sync-external-store": "1.1.0"
},
"peerDependencies": {
"fibers": ">= 3.1.0",
Expand Down Expand Up @@ -260,7 +261,6 @@
"tty-browserify": "0.0.1",
"ua-parser-js": "0.7.28",
"unistore": "3.4.1",
"use-subscription": "1.5.1",
"util": "0.12.4",
"uuid": "8.3.2",
"vm-browserify": "1.1.2",
Expand Down
11 changes: 9 additions & 2 deletions packages/next/shared/lib/loadable.js
Expand Up @@ -22,7 +22,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
// Modified to be compatible with webpack 4 / Next.js

import React from 'react'
import { useSubscription } from 'next/dist/compiled/use-subscription'
import { useSyncExternalStore } from 'use-sync-external-store/shim'

import { LoadableContext } from './loadable-context'

const ALL_INITIALIZERS = []
Expand Down Expand Up @@ -75,6 +76,7 @@ function createLoadableComponent(loadFn, options) {
opts.lazy = React.lazy(opts.loader)
}

/** @type LoadableSubscription */
let subscription = null
function init() {
if (!subscription) {
Expand Down Expand Up @@ -116,7 +118,12 @@ function createLoadableComponent(loadFn, options) {
init()

const context = React.useContext(LoadableContext)
const state = useSubscription(subscription)
const state = useSyncExternalStore(
subscription.subscribe,
subscription.getCurrentValue,
subscription.getCurrentValue
)

React.useImperativeHandle(
ref,
() => ({
Expand Down
19 changes: 0 additions & 19 deletions packages/next/taskfile.js
Expand Up @@ -306,24 +306,6 @@ export async function ncc_react_refresh_utils(task, opts) {
}
}

// eslint-disable-next-line camelcase
export async function ncc_use_subscription(task, opts) {
await task
.source(
opts.src || relative(__dirname, require.resolve('use-subscription'))
)
.ncc({
packageName: 'use-subscription',
externals: {
...externals,
react: 'react',
'react-dom': 'react-dom',
},
target: 'es5',
})
.target('compiled/use-subscription')
}

// eslint-disable-next-line camelcase
externals['chalk'] = 'next/dist/compiled/chalk'
export async function ncc_chalk(task, opts) {
Expand Down Expand Up @@ -1652,7 +1634,6 @@ export async function ncc(task, opts) {
'ncc_node_html_parser',
'ncc_watchpack',
'ncc_chalk',
'ncc_use_subscription',
'ncc_napirs_triples',
'ncc_etag',
'ncc_p_limit',
Expand Down
10 changes: 4 additions & 6 deletions yarn.lock
Expand Up @@ -21248,12 +21248,10 @@ url@^0.11.0:
punycode "1.3.2"
querystring "0.2.0"

use-subscription@1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"
integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA==
dependencies:
object-assign "^4.1.1"
use-sync-external-store@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82"
integrity sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==

use@^3.1.0:
version "3.1.1"
Expand Down

0 comments on commit 26459ef

Please sign in to comment.