useSyncExternalStore
Check out the official React docs!
For more detailed information about React concepts and APIs, please refer to the official documentation for useSyncExternalStore.
useSyncExternalStore is a hook that lets you subscribe to an external store.
UseSyncExternalStore is useful to read and subscribe to a value from a data source that is not part of React's standard state management.
This hook is commonly used by third-party state libraries and for subscribing to browser API's such as getting the current theme (dark mode) or online status.
let getSnapshot() =
window.innerWidth
let subscribe callback =
let handler = fun (_: Browser.Types.Event) -> callback()
window.addEventListener("resize", handler)
fun () -> window.removeEventListener("resize", handler)
[<ReactComponent(true)>]
let UseSyncExternalStore() =
let currentWidth = React.useSyncExternalStore(subscribe, getSnapshot)
Html.h2 $"Window width: {currentWidth}px"
Window width: 1024px
Show code
module Example.UseSyncExternalStore
open Feliz
open Browser
let getSnapshot() =
window.innerWidth
let getServerSnapshot() =
1024.0 // Default server width
let subscribe callback =
let handler = fun (_: Browser.Types.Event) -> callback()
window.addEventListener("resize", handler)
fun () -> window.removeEventListener("resize", handler)
[<ReactComponent(true)>]
let UseSyncExternalStoreDisposable() =
let currentWidth = React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)
Html.h3 $"Window width: {currentWidth}px"
UseSyncExternalStore with IDisposable
If your subscriber returns an IDisposable, Feliz will automatically call its Dispose method when the component unmounts
Window width: 1024px
Show code
module Example.UseSyncExternalStoreDisposable
open Feliz
open Browser
let getSnapshot() =
window.innerWidth
let getServerSnapshot() =
1024.0 // Default server width
let subscribe callback =
let handler = fun (_: Browser.Types.Event) -> callback()
window.addEventListener("resize", handler)
// Feliz helper to create IDisposable
FsReact.createDisposable(fun () -> window.removeEventListener("resize", handler))
// same as:
// { new IDisposable with member _.Dispose() = window.removeEventListener("resize", handler)}
[<ReactComponent(true)>]
let UseSyncExternalStoreDisposable() =
let currentWidth = React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)
Html.h3 $"Window width: {currentWidth}px"
Fable specifics
Due to the way Fable is packaged most browser API's will require adding specific Fable Browser packages to your project
Example
window.matchMediarequires theFable.Browser.MediaQueryListpackagenavigator.onLinerequires theFable.Browser.Navigatorpackage
Detecting dark mode
open Feliz
open Browser
let isDarkQuery = "(prefers-color-scheme: dark)"
let getSnapshot() =
// Uses the Fable.Browser.MediaQueryList package
window.matchMedia(isDarkQuery).matches
let subscribe callback =
let handler = fun (_: Browser.Types.Event) -> callback()
window.matchMedia(isDarkQuery).addEventListener("change", handler)
fun () -> window.matchMedia(isDarkQuery).removeEventListener("change", handler)
[<ReactComponent(true)>]
let DarkModeStatus() =
let isDarkMode = React.useSyncExternalStore(subscribe, getSnapshot)
match isDarkMode with
| true -> Html.h2 "Currently in dark mode"
| false -> Html.h2 "Currently in light mode"
Detecting online status (with IDisposable)
open Feliz
open Browser
let getSnapshot() =
// Uses the Fable.Browser.Navigator package
navigator.onLine
let subscribe callback =
let onlineHandler = fun (_: Browser.Types.Event) -> callback()
window.addEventListener("online", onlineHandler)
window.addEventListener("offline", onlineHandler)
{ new IDisposable with
member _.Dispose() =
window.removeEventListener("online", onlineHandler)
window.removeEventListener("offline", onlineHandler)
}
[<ReactComponent(true)>]
let OnlineStatus() =
let isOnline = React.useSyncExternalStore(subscribe, getSnapshot)
Html.h2 [
if isOnline then
prop.text "You are online"
else
prop.text "You are offline"
]