diff --git a/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js b/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js index 95f104925b93d..34f46774b188b 100644 --- a/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js +++ b/packages/react-devtools-shell/src/app/InspectableElements/InspectableElements.js @@ -20,6 +20,7 @@ import SimpleValues from './SimpleValues'; import SymbolKeys from './SymbolKeys'; import UseMemoCache from './UseMemoCache'; import UseEffectEvent from './UseEffectEvent'; +import UseSyncExternalStore from './UseSyncExternalStore'; // TODO Add Immutable JS example @@ -38,6 +39,7 @@ export default function InspectableElements(): React.Node { + ); } diff --git a/packages/react-devtools-shell/src/app/InspectableElements/UseSyncExternalStore.js b/packages/react-devtools-shell/src/app/InspectableElements/UseSyncExternalStore.js new file mode 100644 index 0000000000000..decb10b2db2d5 --- /dev/null +++ b/packages/react-devtools-shell/src/app/InspectableElements/UseSyncExternalStore.js @@ -0,0 +1,133 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import * as React from 'react'; + +const {useState, useEffect, useSyncExternalStore} = React; + +// Create a simple external store for demonstratio +function createStore(initialValue: T): { + subscribe: (cb: () => void) => () => any, + getSnapshot: () => T, + setValue: (newValue: T) => void, +} { + let value = initialValue; + const subscribers = new Set<() => void>(); + + return { + subscribe(callback) { + subscribers.add(callback); + return () => subscribers.delete(callback); + }, + getSnapshot() { + return value; + }, + setValue(newValue) { + value = newValue; + subscribers.forEach(callback => callback()); + }, + }; +} + +const counterStore = createStore(0); +const themeStore = createStore('light'); + +export default function UseSyncExternalStore(): React.Node { + return ( + <> +

useSyncExternalStore()

+ + + + + ); +} + +function SingleHookCase(): React.Node { + const count = useSyncExternalStore( + counterStore.subscribe, + counterStore.getSnapshot, + ); + + return ( +
+

Single hook case

+

Count: {count}

+ + +
+ ); +} + +function useCounter() { + const count = useSyncExternalStore( + counterStore.subscribe, + counterStore.getSnapshot, + ); + const [localState, setLocalState] = useState(0); + + useEffect(() => { + // Some effect + }, [count]); + + return {count, localState, setLocalState}; +} + +function HookTreeCase(): React.Node { + const {count, localState, setLocalState} = useCounter(); + + return ( +
+

Hook tree case

+

External count: {count}

+

Local state: {localState}

+ + +
+ ); +} + +function useTheme() { + const theme = useSyncExternalStore( + themeStore.subscribe, + themeStore.getSnapshot, + ); + + return theme; +} + +function MultipleStoresCase() { + const count = useSyncExternalStore( + counterStore.subscribe, + counterStore.getSnapshot, + ); + const theme = useTheme(); + + return ( +
+

Multiple stores case

+

Count: {count}

+

Theme: {theme}

+ +
+ ); +}