{
  "id": 16156657,
  "title": "Your Custom Hooks Tear in React 18. `useSyncExternalStore` Fixes It.",
  "url": "https://urgent.news/2026/10/23/your-custom-hooks-tear-in-react-18-usesyncexternalstore-fixes-it",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-23T06:11:03.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/parsajiravand/your-custom-hooks-tear-in-react-18-usesyncexternalstore-fixes-it-2ogd"
  },
  "original_language": "en",
  "account": "React 18 introduced `useSyncExternalStore`, a fix for the tearing issue caused by concurrent rendering. The hook `useOnlineStatus()` was fine in previous versions, but when wrapped in `startTransition`, it started producing inconsistent results. This happens because `useState` + `useEffect` assumes that once a component commits, it stays committed until the next explicit update, and that all components re-render from the same world. However, concurrent rendering breaks this assumption.\n\n`useSyncExternalStore` allows you to subscribe to external state, such as browser APIs, without running into tearing. It takes three functions: a callback to subscribe to changes, a function to get the current snapshot value, and an optional function for server-side rendering. The key difference is that `getSnapshot` is called every render, and React checks the current value synchronously before committing, effectively closing the gap where tearing occurs.\n\nYou may already be using `useSyncExternalStore` in libraries like Zustand or react-redux, but if you have your own custom hooks, consider using this hook for any state subscriptions that live outside of React. Remember to include the optional `getServerSnapshot` function when rendering on the server to avoid hydration mismatches.",
  "summary": "The header says \"You're offline.\" Three pixels below it, the save button is still clickable, sending requests like nothing's wrong. Same navigator.onLine value. Same render. Two different answers on screen at the same time. You didn't write a new bug. You wrote the hook everyone writes. function useOnlineStatus () { const [ online , setOnline ] = useState ( navigator . onLine ); useEffect (() =>…",
  "key_points": [
    "React 18 introduced useSyncExternalStore to fix tearing issue.",
    "useSyncExternalStore allows subscribing to external state without tearing.",
    "Include getServerSnapshot for server-side rendering to avoid hydration mismatches."
  ],
  "editors_take": "Adopting this specialized hook ensures that external state subscriptions remain consistent during concurrent rendering, preventing the visual inconsistencies that occur when custom hooks bypass React's internal synchronization mechanisms.",
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}