Read external state through a consistent subscription contract.
Read the explanation, run the worked code, then complete the practice lab in Assignments. This advanced lesson includes worked code and a dedicated practice lab.
Understand the idea
Sometimes the source of truth lives outside React: a browser connection flag, an existing store or a library subscription. useSyncExternalStore connects that source through subscribe and getSnapshot. React reads a snapshot for rendering and subscribes to notifications that indicate it should check again.
Keep the subscription function stable to avoid needless resubscription. Return an unsubscribe function that removes exactly the listeners you added. The snapshot must be stable while the underlying data is unchanged; returning a new object every time can cause repeated rendering. Use an immutable cached object for complex stores, or a primitive as this example does.
Server-rendered applications also supply getServerSnapshot. Its initial value must agree between the server output and hydration. Here it returns true as a consistent initial fallback, then the browser snapshot updates after hydration. navigator.onLine is only a browser connectivity hint; it does not prove your API is reachable. Your request error handling must still cope with failed servers, captive portals and timeouts.
Run the example
Use a separate React practice project with a Node.js version supported by Vite. Create it once with these commands, then use its development URL. Do not paste this into the Edupoly website’s own source files.
npm create vite@latest react-practice -- --template react
cd react-practice
npm install
npm run dev
Replace src/App.jsx with the following complete example. Keep Vite’s generated src/main.jsx entry point.
src/App.jsx
import { useSyncExternalStore } from 'react';
function subscribe(notify) {
window.addEventListener('online', notify); window.addEventListener('offline', notify);
return () => {window.removeEventListener('online', notify); window.removeEventListener('offline', notify);};
}
function getSnapshot() { return navigator.onLine; }
function getServerSnapshot() { return true; }
function useOnline() {return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);}
export default function App() {
const online = useOnline();
return <main><h1>Connection indicator</h1><p role="status">{online ? 'Browser reports online' : 'Browser reports offline'}</p><p>This does not guarantee that the API is available.</p></main>;
}
Expected result
The indicator follows the browser’s online/offline signal. Toggling the browser’s offline simulation may trigger it; verify in your browser instead of assuming every simulation emits the same event.
Apply this to your assignments
Mount two indicators and verify they agree when connectivity events occur. Unmount one and confirm its listeners are removed. Extend a small external counter store with a cached snapshot and notify subscribers after a change.
Practice starting point
Use the worked example above as your starting point.
Open Assignments for this lesson’s practice lab and acceptance checks.
Common mistakes
Do not return a newly allocated object from getSnapshot on every call. Do not treat online as proof that a save succeeded. Always unsubscribe.
Check your understanding
- Predict the output before running the example, then compare it with the result panel.
- Explain which value each expression reads and which action changes it.
- Try the boundary cases listed in the practice task and record what you observe.
- Rebuild one matching assignment without copying, then compare behavior with the original example.
Reference
Official documentation for this topic · Vite setup requirements
