@@ -24,6 +24,7 @@ import { assign, IS_NON_DIMENSIONAL } from './util';
2424export const REACT_ELEMENT_TYPE = Symbol . for ( 'react.element' ) ;
2525
2626const MODE_HYDRATE = 1 << 5 ;
27+ let currentComponent , hydrationRoot , renderTrackingInitialized ;
2728
2829const CAMEL_PROPS =
2930 / ^ (?: a c c e n t | a l i g n m e n t | a r a b i c | b a s e l i n e | c a p | c l i p (? ! P a t h U ) | c o l o r | d o m i n a n t | f i l l | f l o o d | f o n t | g l y p h (? ! R ) | h o r i z | i m a g e ( ! S ) | l e t t e r | l i g h t i n g | m a r k e r (? ! H | W | U ) | o v e r l i n e | p a i n t | p o i n t e r | s h a p e | s t o p | s t r i k e t h r o u g h | s t r o k e | t e x t (? ! L ) | t r a n s f o r m | u n d e r l i n e | u n i c o d e | u n i t s | v | v e c t o r | v e r t | w o r d | w r i t i n g | x (? ! C ) ) [ A - Z ] / ;
@@ -35,47 +36,45 @@ const IS_DOM = typeof document != 'undefined';
3536 * on a high level this cuts out the warnings, ... and attempts a smaller implementation
3637 * @typedef {{ _value: any; _getSnapshot: () => any } } Store
3738 */
38- export function useSyncExternalStore (
39- subscribe ,
40- getSnapshot ,
41- getServerSnapshot
42- ) {
43- const serverRendering = options . _skipEffects || hydrationRoot ;
44- const value = serverRendering
45- ? ( getServerSnapshot || getSnapshot ) ( )
46- : getSnapshot ( ) ;
47-
48- /**
49- * @typedef {{ _instance: Store } } StoreRef
50- * @type {[StoreRef, (store: StoreRef) => void] }
51- */
52- const [ { _instance } , forceUpdate ] = useState ( {
53- _instance : { _value : value , _getSnapshot : getSnapshot }
54- } ) ;
55-
56- useLayoutEffect ( ( ) => {
57- _instance . _value = value ;
58- _instance . _getSnapshot = getSnapshot ;
39+ export const useSyncExternalStore = /* @__PURE__ */ initRenderTracking (
40+ function useSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) {
41+ const serverRendering = options . _skipEffects || hydrationRoot ;
42+ const value = serverRendering
43+ ? ( getServerSnapshot || getSnapshot ) ( )
44+ : getSnapshot ( ) ;
45+
46+ /**
47+ * @typedef {{ _instance: Store } } StoreRef
48+ * @type {[StoreRef, (store: StoreRef) => void] }
49+ */
50+ const [ { _instance } , forceUpdate ] = useState ( {
51+ _instance : { _value : value , _getSnapshot : getSnapshot }
52+ } ) ;
5953
60- if ( didSnapshotChange ( _instance ) ) {
61- forceUpdate ( { _instance } ) ;
62- }
63- } , [ subscribe , value , getSnapshot ] ) ;
54+ useLayoutEffect ( ( ) => {
55+ _instance . _value = value ;
56+ _instance . _getSnapshot = getSnapshot ;
6457
65- useEffect ( ( ) => {
66- if ( didSnapshotChange ( _instance ) ) {
67- forceUpdate ( { _instance } ) ;
68- }
58+ if ( didSnapshotChange ( _instance ) ) {
59+ forceUpdate ( { _instance } ) ;
60+ }
61+ } , [ subscribe , value , getSnapshot ] ) ;
6962
70- return subscribe ( ( ) => {
63+ useEffect ( ( ) => {
7164 if ( didSnapshotChange ( _instance ) ) {
7265 forceUpdate ( { _instance } ) ;
7366 }
74- } ) ;
75- } , [ subscribe ] ) ;
7667
77- return value ;
78- }
68+ return subscribe ( ( ) => {
69+ if ( didSnapshotChange ( _instance ) ) {
70+ forceUpdate ( { _instance } ) ;
71+ }
72+ } ) ;
73+ } , [ subscribe ] ) ;
74+
75+ return value ;
76+ }
77+ ) ;
7978
8079/** @type {(inst: Store) => boolean } */
8180function didSnapshotChange ( inst ) {
@@ -310,17 +309,6 @@ options.vnode = vnode => {
310309 if ( oldVNodeHook ) oldVNodeHook ( vnode ) ;
311310} ;
312311
313- // Only needed for react-relay
314- let currentComponent , hydrationRoot ;
315- const oldBeforeRender = options . _render ;
316- options . _render = function ( vnode ) {
317- if ( oldBeforeRender ) {
318- oldBeforeRender ( vnode ) ;
319- }
320- if ( vnode . _flags & MODE_HYDRATE ) hydrationRoot = vnode ;
321- currentComponent = vnode . _component ;
322- } ;
323-
324312const oldDiffed = options . diffed ;
325313/** @type {(vnode: import('./internal').VNode) => void } */
326314options . diffed = function ( vnode ) {
@@ -339,19 +327,39 @@ options.diffed = function (vnode) {
339327 ) {
340328 dom . value = props . value == null ? '' : props . value ;
341329 }
342-
343- currentComponent = null ;
344- if ( hydrationRoot == vnode ) hydrationRoot = null ;
345330} ;
346331
332+ // Only needed for react-relay and useSyncExternalStore hydration.
333+ function initRenderTracking ( value ) {
334+ if ( ! renderTrackingInitialized ) {
335+ renderTrackingInitialized = true ;
336+
337+ const oldBeforeRender = options . _render ;
338+ options . _render = vnode => {
339+ if ( oldBeforeRender ) oldBeforeRender ( vnode ) ;
340+ if ( vnode . _flags & MODE_HYDRATE ) hydrationRoot = vnode ;
341+ currentComponent = vnode . _component ;
342+ } ;
343+
344+ const oldDiffed = options . diffed ;
345+ options . diffed = vnode => {
346+ if ( oldDiffed ) oldDiffed ( vnode ) ;
347+ currentComponent = null ;
348+ if ( hydrationRoot == vnode ) hydrationRoot = null ;
349+ } ;
350+ }
351+
352+ return value ;
353+ }
354+
347355/**
348356 * Read the value of a Promise (suspending while pending) or a Context.
349357 * Unlike other hooks, `use` may be called conditionally.
350358 * @template T
351359 * @param {(Promise<T> & { status?: string, value?: T, reason?: any }) | import('../../src/internal').PreactContext } resource
352360 * @returns {T }
353361 */
354- export const use = resource => {
362+ export const use = /* @__PURE__ */ initRenderTracking ( function use ( resource ) {
355363 // A Context is a function without a `then`, a thenable has one.
356364 if ( resource . then ) {
357365 if ( resource . status == 'fulfilled' ) return resource . value ;
@@ -383,7 +391,7 @@ export const use = resource => {
383391 provider . sub ( currentComponent ) ;
384392 }
385393 return provider . props . value ;
386- } ;
394+ } ) ;
387395
388396// This is a very very private internal function for React it
389397// is used to sort-of do runtime dependency injection.
0 commit comments