mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 00:20:04 +01:00
[DevTools] chore: add useSyncExternalStore examples to shell (#34932)
Few examples of using `useSyncExternalStore` that can be useful for debugging hook tree reconstruction logic and hook names parsing feature.
This commit is contained in:
parent
ea0c17b095
commit
613cf80f26
|
|
@ -20,6 +20,7 @@ import SimpleValues from './SimpleValues';
|
||||||
import SymbolKeys from './SymbolKeys';
|
import SymbolKeys from './SymbolKeys';
|
||||||
import UseMemoCache from './UseMemoCache';
|
import UseMemoCache from './UseMemoCache';
|
||||||
import UseEffectEvent from './UseEffectEvent';
|
import UseEffectEvent from './UseEffectEvent';
|
||||||
|
import UseSyncExternalStore from './UseSyncExternalStore';
|
||||||
|
|
||||||
// TODO Add Immutable JS example
|
// TODO Add Immutable JS example
|
||||||
|
|
||||||
|
|
@ -38,6 +39,7 @@ export default function InspectableElements(): React.Node {
|
||||||
<SymbolKeys />
|
<SymbolKeys />
|
||||||
<UseMemoCache />
|
<UseMemoCache />
|
||||||
<UseEffectEvent />
|
<UseEffectEvent />
|
||||||
|
<UseSyncExternalStore />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
133
packages/react-devtools-shell/src/app/InspectableElements/UseSyncExternalStore.js
vendored
Normal file
133
packages/react-devtools-shell/src/app/InspectableElements/UseSyncExternalStore.js
vendored
Normal file
|
|
@ -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<T>(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 (
|
||||||
|
<>
|
||||||
|
<h2>useSyncExternalStore()</h2>
|
||||||
|
<SingleHookCase />
|
||||||
|
<HookTreeCase />
|
||||||
|
<MultipleStoresCase />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SingleHookCase(): React.Node {
|
||||||
|
const count = useSyncExternalStore(
|
||||||
|
counterStore.subscribe,
|
||||||
|
counterStore.getSnapshot,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>Single hook case</h3>
|
||||||
|
<p>Count: {count}</p>
|
||||||
|
<button onClick={() => counterStore.setValue(count + 1)}>
|
||||||
|
Increment
|
||||||
|
</button>
|
||||||
|
<button onClick={() => counterStore.setValue(count - 1)}>
|
||||||
|
Decrement
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div>
|
||||||
|
<h3>Hook tree case</h3>
|
||||||
|
<p>External count: {count}</p>
|
||||||
|
<p>Local state: {localState}</p>
|
||||||
|
<button onClick={() => counterStore.setValue(count + 1)}>
|
||||||
|
Increment External
|
||||||
|
</button>
|
||||||
|
<button onClick={() => setLocalState(localState + 1)}>
|
||||||
|
Increment Local
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useTheme() {
|
||||||
|
const theme = useSyncExternalStore(
|
||||||
|
themeStore.subscribe,
|
||||||
|
themeStore.getSnapshot,
|
||||||
|
);
|
||||||
|
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MultipleStoresCase() {
|
||||||
|
const count = useSyncExternalStore(
|
||||||
|
counterStore.subscribe,
|
||||||
|
counterStore.getSnapshot,
|
||||||
|
);
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{background: theme === 'dark' ? '#333' : '#fff'}}>
|
||||||
|
<h3>Multiple stores case</h3>
|
||||||
|
<p>Count: {count}</p>
|
||||||
|
<p>Theme: {theme}</p>
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
themeStore.setValue(theme === 'light' ? 'dark' : 'light')
|
||||||
|
}>
|
||||||
|
Toggle Theme
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user