diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 00e49ba..0d4a290 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"fable": {
- "version": "4.9.0",
+ "version": "4.7.0",
"commands": [
"fable"
]
diff --git a/src/ElmishStore.Example/ElmishStore.Example.fsproj b/src/ElmishStore.Example/ElmishStore.Example.fsproj
index 7efec8c..47d5555 100644
--- a/src/ElmishStore.Example/ElmishStore.Example.fsproj
+++ b/src/ElmishStore.Example/ElmishStore.Example.fsproj
@@ -1,4 +1,4 @@
-
+
net8.0
@@ -31,8 +31,9 @@
+
-
\ No newline at end of file
+
diff --git a/src/ElmishStore.Example/ModelStore.fs b/src/ElmishStore.Example/ModelStore.fs
index 5929837..87698a1 100644
--- a/src/ElmishStore.Example/ModelStore.fs
+++ b/src/ElmishStore.Example/ModelStore.fs
@@ -11,19 +11,35 @@ open Elmish.Debug
#endif
-let store =
- Program.mkProgram init update (fun _ _ -> ())
- #if DEBUG
- |> Program.withConsoleTrace
- |> Program.withDebugger
- #endif
- |> ElmishStore.createStore "main"
+// One additional step (comparing with the previous module-based API).
+// However, creating the Host on the global level is essentially the same as using the module-based API.
+let storesHost = ElmishStoresHost()
+let store =
+ let program =
+ Program.mkProgram init update (fun _ _ -> ())
+ #if DEBUG
+ |> Program.withConsoleTrace
+ |> Program.withDebugger
+ #endif
+ storesHost.create "main" program
+
+(*// Previous API:
[]
let useSelector (selector: Model -> 'a) = React.useElmishStore (store, selector)
[]
let useSelectorMemoized (memoizedSelector: Model -> 'a) =
- React.useElmishStoreMemoized (store, memoizedSelector)
+ React.useElmishStoreMemoized (store, memoizedSelector)
+*)
+
+// Instead of defining separate custom hooks for a specific Store,
+// just create all the Store-related hooks packed in an object.
+let storeApi = StoreApi.getElmishStoreApi store
+
+// These helpers should be inline so that Fable doesn't generate unnecessary extra-functions around the hooks.
+// However, these helpers aren't really needed, as the hooks could be called directly from the `storeApi` value.
+let inline useSelector selector = storeApi.useSelector selector
+let inline useSelectorMemoized selector = storeApi.useSelectorMemoized selector
let dispatch = store.Dispatch
\ No newline at end of file
diff --git a/src/ElmishStore/ElmishStore.fs b/src/ElmishStore/ElmishStore.fs
index 2abd430..3000cdc 100644
--- a/src/ElmishStore/ElmishStore.fs
+++ b/src/ElmishStore/ElmishStore.fs
@@ -6,134 +6,277 @@ open Fable.Core
open ElmishStore
open System.Collections.Generic
-type ElmishStore<'model, 'msg> = {
- GetModel: unit -> 'model
- Dispatch: 'msg -> unit
- Subscribe: UseSyncExternalStoreSubscribe
+type ElmishStore<'Model, 'Msg> = {
+ GetModel: unit -> 'Model
+ Dispatch: 'Msg -> unit
+ Subscribe: UseSyncExternalStoreSubscribe
}
-type private StoreState<'arg, 'model, 'msg> = {
- Store: ElmishStore<'model, 'msg>
- SetTermination: bool -> unit
+type private StoreState<'Arg, 'Model, 'Msg> = {
+ Store: ElmishStore<'Model, 'Msg>
+ SetTermination: bool -> unit
}
-module ElmishStore =
+type internal StoreKey<'T when 'T : equality> = 'T
- let mutable private stores: Dictionary = Dictionary()
+type IElmishProgramBasedStoreInitializer<'StoreKey when StoreKey<'StoreKey>> =
+ abstract CreateStore :
+ program: Program *
+ storeKey: 'StoreKey ->
+ ElmishStore<'Model, 'Msg>
+ abstract CreateStoreWithArg :
+ program: Program<'Arg, 'Model, 'Msg, unit> *
+ storeKey: 'StoreKey *
+ arg: 'Arg ->
+ ElmishStore<'Model, 'Msg>
- let private initiate
- uniqueName
- (arg: 'arg)
- (program: Program<'arg, 'model, 'msg, unit>)
- (getState: unit -> 'model option)
- =
+type IElmishFunctionsBasedStoreInitializer<'StoreKey when StoreKey<'StoreKey>> =
+ abstract CreateStoreWithFunctions :
+ init: (unit -> 'Model * Cmd<'Msg>) *
+ update: ('Msg -> 'Model -> 'Model * Cmd<'Msg>) *
+ storeKey: 'StoreKey ->
+ ElmishStore<'Model, 'Msg>
+ abstract CreateStoreWithFunctionsAndArg :
+ init: ('Arg -> 'Model * Cmd<'Msg>) *
+ update: ('Msg -> 'Model -> 'Model * Cmd<'Msg>) *
+ storeKey: 'StoreKey *
+ arg: 'Arg ->
+ ElmishStore<'Model, 'Msg>
- let mutable state = getState ()
- let mutable finalDispatch = None
- let mutable shouldTerminate = false
+type IElmishStoreInitializer<'StoreKey when StoreKey<'StoreKey>> =
+ inherit IElmishFunctionsBasedStoreInitializer<'StoreKey>
+ inherit IElmishProgramBasedStoreInitializer<'StoreKey>
- let setTermination should = shouldTerminate <- should
+type IElmishStoreAccessor<'StoreKey when StoreKey<'StoreKey>> =
+ abstract GetStore<'Model, 'Msg when StoreKey<'StoreKey>> :
+ storeKey: 'StoreKey -> ElmishStore<'Model, 'Msg>
+ abstract TryGetStore<'Model, 'Msg when StoreKey<'StoreKey>> :
+ storeKey: 'StoreKey -> ElmishStore<'Model, 'Msg> option
- let dispatch msg =
- match finalDispatch with
- | Some finalDispatch -> finalDispatch msg
- | None -> failwith "You're using initial dispatch. That shouldn't happen."
+type IElmishStoresHost<'StoreKey when StoreKey<'StoreKey>> =
+ inherit IElmishStoreInitializer<'StoreKey>
+ inherit IElmishStoreAccessor<'StoreKey>
- let subscribers = ResizeArray unit>()
- let subscribe callback =
- subscribers.Add(callback)
- fun () -> subscribers.Remove(callback) |> ignore
+type ElmishStoresHost<'StoreKey when StoreKey<'StoreKey>>() =
- let mapSetState setState model dispatch =
- setState model dispatch
- let oldModel = state
- state <- Some model
- finalDispatch <- Some dispatch
- // Skip re-renders if model hasn't changed
- if not (obj.ReferenceEquals(model, oldModel)) then
- subscribers |> Seq.iter (fun callback -> callback ())
+ let mutable stores: Dictionary<'StoreKey, obj> = Dictionary<'StoreKey, obj>()
- let mapInit userInit arg =
- if state.IsSome then state.Value, Cmd.none else userInit arg
+ let initiate
+ storeKey
+ (arg: 'Arg)
+ (program: Program<'Arg, 'Model, 'Msg, unit>)
+ (getState: unit -> 'Model option)
+ =
+ let mutable state = getState ()
+ let mutable finalDispatch = None
+ let mutable shouldTerminate = false
- let mapTermination (predicate, terminate) =
- let pred msg = predicate msg || shouldTerminate
- pred, terminate
+ let setTermination should = shouldTerminate <- should
- program
- |> Program.map mapInit id id mapSetState id mapTermination
- |> Program.runWith arg
+ let dispatch msg =
+ match finalDispatch with
+ | Some finalDispatch -> finalDispatch msg
+ | None -> failwith "You're using initial dispatch. That shouldn't happen."
- let getState () =
- match state with
- | Some state -> state
- | None -> failwith "State is not initialized. That shouldn't happen."
+ let subscribers = ResizeArray unit>()
- let store = {
- GetModel = getState
- Dispatch = dispatch
- Subscribe = UseSyncExternalStoreSubscribe subscribe
- }
+ let subscribe callback =
+ subscribers.Add(callback)
+ fun () -> subscribers.Remove(callback) |> ignore
- let storeState = {
- Store = store
- SetTermination = setTermination
- }
+ let mapSetState setState model dispatch =
+ setState model dispatch
+ let oldModel = state
+ state <- Some model
+ finalDispatch <- Some dispatch
+ // Skip re-renders if model hasn't changed
+ if not (obj.ReferenceEquals(model, oldModel)) then
+ subscribers |> Seq.iter (fun callback -> callback ())
- stores[uniqueName] <- box storeState
- store
+ let mapInit userInit arg =
+ if state.IsSome then state.Value, Cmd.none else userInit arg
- let createStoreWith uniqueName (arg: 'arg) (program: Program<'arg, 'model, 'msg, unit>) =
+ let mapTermination (predicate, terminate) =
+ let pred msg = predicate msg || shouldTerminate
+ pred, terminate
- let getState =
- if stores.ContainsKey(uniqueName) then
- let storeState = stores[uniqueName] |> unbox>
- storeState.SetTermination true
- (fun () -> Some(storeState.Store.GetModel()))
- else
- (fun () -> None)
+ program
+ |> Program.map mapInit id id mapSetState id mapTermination
+ |> Program.runWith arg
- initiate uniqueName arg program getState
+ let getState () =
+ match state with
+ | Some state -> state
+ | None -> failwith "State is not initialized. That shouldn't happen."
+
+ let store = {
+ GetModel = getState
+ Dispatch = dispatch
+ Subscribe = UseSyncExternalStoreSubscribe subscribe
+ }
+
+ let storeState = {
+ Store = store
+ SetTermination = setTermination
+ }
+
+ stores[storeKey] <- box storeState
+ store
+
+ let createStoreWith storeKey (arg: 'Arg) (program: Program<'Arg, 'Model, 'Msg, unit>) =
+
+ let getState =
+ if stores.ContainsKey(storeKey) then
+ let storeState = stores[storeKey] |> unbox>
+ storeState.SetTermination true
+ (fun () -> Some(storeState.Store.GetModel()))
+ else
+ (fun () -> None)
+
+ initiate storeKey arg program getState
+
+ let createStore storeKey program : ElmishStore<'Model, 'Msg> =
+ createStoreWith storeKey () program
+
+ interface IElmishStoresHost<'StoreKey> with
+
+ member this.CreateStore(program: Program, storeKey: StoreKey<'StoreKey>) =
+ createStore storeKey program
+
+ member this.CreateStoreWithArg(program: Program<'Arg, 'Model, 'Msg, unit>, storeKey, arg) =
+ createStoreWith storeKey arg program
+
+ member this.CreateStoreWithFunctions(
+ init: unit -> 'Model * Cmd<'Msg>,
+ update: 'Msg -> 'Model -> 'Model * Cmd<'Msg>,
+ storeKey
+ ) =
+ let program = Program.mkProgram init update (fun _ _ -> ())
+ (this :> IElmishStoresHost<'StoreKey>).CreateStore(program, storeKey)
+
+ member this.CreateStoreWithFunctionsAndArg(
+ init: 'Arg -> 'Model * Cmd<'Msg>,
+ update: 'Msg -> 'Model -> 'Model * Cmd<'Msg>,
+ storeKey,
+ arg: 'Arg
+ ) =
+ let program = Program.mkProgram init update (fun _ _ -> ())
+ (this :> IElmishStoresHost<'StoreKey>).CreateStoreWithArg(program, storeKey, arg)
+
+ member this.GetStore<'Model, 'Msg>(storeKey) =
+ try
+ let storeState =
+ stores[storeKey] |> unbox>
+ storeState.Store
+ with
+ | :? KeyNotFoundException as e ->
+ failwithf
+ $"Elmish Store with key %A{storeKey} hasn't been found. Store has to be created before it can be accessed."
+
+ member this.TryGetStore<'Model, 'Msg> storeKey =
+ match stores.TryGetValue storeKey with
+ | true, s ->
+ let storeState = unbox> s
+ Some storeState.Store
+ | false, _ -> None
+
+ // The following functions have to be inlined because JS doesn't support methods overloading.
+
+ member inline this.CreateStore(program: Program, storeKey) =
+ (this :> IElmishStoresHost<'StoreKey>).CreateStore(program, storeKey)
+
+ member inline this.CreateStore(program: Program<'Arg, 'Model, 'Msg, unit>, storeKey, arg) =
+ (this :> IElmishStoresHost<'StoreKey>).CreateStoreWithArg(program, storeKey, arg)
+
+ member inline this.CreateStore(
+ init: unit -> 'Model * Cmd<'Msg>,
+ update: 'Msg -> 'Model -> 'Model * Cmd<'Msg>,
+ storeKey
+ ) =
+ (this :> IElmishStoresHost<'StoreKey>).CreateStoreWithFunctions(init, update, storeKey)
+
+ member inline this.CreateStore(
+ init: 'Arg -> 'Model * Cmd<'Msg>,
+ update: 'Msg -> 'Model -> 'Model * Cmd<'Msg>,
+ storeKey,
+ arg: 'Arg
+ ) =
+ let program = Program.mkProgram init update (fun _ _ -> ())
+ (this :> IElmishStoresHost<'StoreKey>).CreateStoreWithArg(program, storeKey, arg)
+
+ member inline this.GetStore storeKey =
+ (this :> IElmishStoreAccessor<'StoreKey>).GetStore storeKey
+
+ member inline this.TryGetStore storeKey =
+ (this :> IElmishStoreAccessor<'StoreKey>).TryGetStore storeKey
- let inline createStore uniqueName program : ElmishStore<'model, 'msg> =
- createStoreWith uniqueName () program
[]
type ElmishStore =
- static member Create
- (
- program: Program<'arg, 'model, 'msg, unit>,
- arg: 'arg,
- uniqueName
- ) : ElmishStore<'model, 'msg> =
- ElmishStore.createStoreWith uniqueName arg program
-
- static member inline Create(program: Program, uniqueName) =
- ElmishStore.Create(program, (), uniqueName)
-
- static member inline Create
- (
- init: 'arg -> 'model * Cmd<'msg>,
- update: 'msg -> 'model -> 'model * Cmd<'msg>,
- arg: 'arg,
- uniqueName
- ) =
- ElmishStore.Create((Program.mkProgram init update (fun _ _ -> ())), arg, uniqueName)
-
- static member inline Create
- (
- init: unit -> 'model * Cmd<'msg>,
- update: 'msg -> 'model -> 'model * Cmd<'msg>,
- uniqueName
- ) =
- ElmishStore.Create(Program.mkProgram init update (fun _ _ -> ()), uniqueName)
-
- static member inline Create
- (
- init: 'model * Cmd<'msg>,
- update: 'msg -> 'model -> 'model * Cmd<'msg>,
- uniqueName
- ) =
- ElmishStore.Create(Program.mkProgram (fun () -> init) update (fun _ _ -> ()), uniqueName)
+ static member inline create
+ (host: IElmishStoresHost<'StoreKey>)
+ storeKey
+ (program: Program)
+ =
+ host.CreateStore(program, storeKey)
+
+ static member inline createWithArg
+ (host: IElmishStoresHost<'StoreKey>)
+ storeKey
+ arg
+ (program: Program<'Arg, 'Model, 'Msg, unit>)
+ =
+ host.CreateStoreWithArg(program, storeKey, arg)
+
+ static member inline createWithFunctions
+ (host: IElmishStoresHost<'StoreKey>)
+ storeKey
+ (init: unit -> 'Model * Cmd<'Msg>)
+ update
+ =
+ host.CreateStoreWithFunctions(init, update, storeKey)
+
+ static member inline createWithFunctionsAndArg
+ (host: IElmishStoresHost<'StoreKey>)
+ storeKey
+ arg
+ (init: 'Arg -> 'Model * Cmd<'Msg>)
+ update
+ =
+ host.CreateStoreWithFunctionsAndArg(init, update, storeKey, arg)
+
+
+[]
+module Extensions =
+
+ type IElmishStoresHost<'StoreKey when StoreKey<'StoreKey>> with
+
+ member inline this.create
+ storeKey
+ (program: Program)
+ =
+ this.CreateStore(program, storeKey)
+
+ member inline this.createWithArg
+ storeKey
+ arg
+ (program: Program<'Arg, 'Model, 'Msg, unit>)
+ =
+ this.CreateStoreWithArg(program, storeKey, arg)
+
+ member inline this.createWithFunctions
+ storeKey
+ (init: unit -> 'Model * Cmd<'Msg>)
+ update
+ =
+ this.CreateStoreWithFunctions(init, update, storeKey)
+
+ member inline this.createWithFunctionsAndArg
+ storeKey
+ arg
+ (init: 'Arg -> 'Model * Cmd<'Msg>)
+ update
+ =
+ this.CreateStoreWithFunctionsAndArg(init, update, storeKey, arg)
diff --git a/src/ElmishStore/ElmishStore.fsproj b/src/ElmishStore/ElmishStore.fsproj
index 19c0958..10a0539 100644
--- a/src/ElmishStore/ElmishStore.fsproj
+++ b/src/ElmishStore/ElmishStore.fsproj
@@ -1,35 +1,42 @@
-
+
-
- Elmish.Store
- A library that merges Elmish and React, providing an external store with efficient, selective component rendering capabilities.
- fsharp;fable;react;elmish
- Łukasz Krzywizna
- SelectView Data Solutions
- 0.1.0
- net8.0
- readme.md
- https://github.com/SelectViewData/elmish-store
- git
- MIT
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+ Elmish.Store
+ A library that merges Elmish and React, providing an external store with efficient, selective component rendering capabilities.
+ fsharp;fable;react;elmish
+ Łukasz Krzywizna
+ SelectView Data Solutions
+ 0.3.0-beta.1
+ net6.0
+ readme.md
+ https://github.com/SelectViewData/elmish-store
+ git
+ MIT
+
+
+ fable-javascript
+ library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ElmishStore/Extensions.fs b/src/ElmishStore/Extensions.fs
new file mode 100644
index 0000000..e24c5b5
--- /dev/null
+++ b/src/ElmishStore/Extensions.fs
@@ -0,0 +1,23 @@
+namespace ElmishStore
+
+open Fable.Core
+open Feliz
+open ElmishStore
+
+[]
+type React =
+
+ /// Provides a current snapshot of the store's state selected by the selector function.
+ /// NOTE: Selector returning value needs to be referentially stable.
+ static member inline useElmishStore(store, selector: 'model -> 'a) =
+ Hooks.useElmishStore store selector
+
+ /// Provides a current snapshot of the store's state selected by the selector function.
+ /// The result of the selector function is memoized and compared with isEqual function.
+ static member inline useElmishStoreMemoized(store, selector: 'model -> 'a, isEqual) =
+ Hooks.useElmishStoreMemoizedWithCustomEquality store selector isEqual
+
+ /// Provides a current snapshot of the store's state selected by the selector function.
+ /// The result of the selector function is memoized and compared with structural equality.
+ static member inline useElmishStoreMemoized(store, selector: 'model -> 'a) =
+ Hooks.useElmishStoreMemoized store selector
\ No newline at end of file
diff --git a/src/ElmishStore/Hooks.fs b/src/ElmishStore/Hooks.fs
index f904da6..fa4aab5 100644
--- a/src/ElmishStore/Hooks.fs
+++ b/src/ElmishStore/Hooks.fs
@@ -1,49 +1,47 @@
-namespace ElmishStore
+module ElmishStore.Hooks
open Fable.Core
open Feliz
open ElmishStore
-[]
-type React =
- /// Provides a current snapshot of the store's state selected by the selector function.
- /// NOTE: Selector returning value needs to be referentially stable.
- []
- static member useElmishStore(store, selector: 'model -> 'a) =
+/// Provides a current snapshot of the store's state selected by the selector function.
+/// NOTE: Selector returning value needs to be referentially stable.
+[]
+let useElmishStore store (selector: 'model -> 'a) =
ReactBindings.useSyncExternalStore (
- store.Subscribe,
- React.useCallback (
- (fun () -> store.GetModel() |> selector),
- [| box store; box selector |]
- )
+ store.Subscribe,
+ React.useCallback (
+ (fun () -> store.GetModel() |> selector),
+ [| box store; box selector |]
+ )
)
- /// Provides a current snapshot of the store's state selected by the selector function.
- /// The result of the selector function is memoized and compared with isEqual function.
- []
- static member useElmishStoreMemoized(store, selector: 'model -> 'a, isEqual) =
+/// Provides a current snapshot of the store's state selected by the selector function.
+/// The result of the selector function is memoized and compared with isEqual function.
+[]
+let useElmishStoreMemoizedWithCustomEquality store (selector: 'model -> 'a) isEqual =
ReactBindings.useSyncExternalStoreWithSelector (
- store.Subscribe,
- React.useCallback(
- (fun () -> store.GetModel()),
- [| box store; box selector |]
- ),
- selector,
- isEqual
+ store.Subscribe,
+ React.useCallback(
+ (fun () -> store.GetModel()),
+ [| box store; box selector |]
+ ),
+ selector,
+ isEqual
)
- /// Provides a current snapshot of the store's state selected by the selector function.
- /// The result of the selector function is memoized and compared with structural equality.
- []
- static member useElmishStoreMemoized(store, selector: 'model -> 'a) =
+/// Provides a current snapshot of the store's state selected by the selector function.
+/// The result of the selector function is memoized and compared with structural equality.
+[]
+let useElmishStoreMemoized store (selector: 'model -> 'a) =
ReactBindings.useSyncExternalStoreWithSelector (
- store.Subscribe,
- React.useCallback(
- (fun () -> store.GetModel()),
- [| box store; box selector |]
- ),
- selector,
- (=)
+ store.Subscribe,
+ React.useCallback(
+ (fun () -> store.GetModel()),
+ [| box store; box selector |]
+ ),
+ selector,
+ (=)
)
diff --git a/src/ElmishStore/StoreApi.fs b/src/ElmishStore/StoreApi.fs
new file mode 100644
index 0000000..ac64c96
--- /dev/null
+++ b/src/ElmishStore/StoreApi.fs
@@ -0,0 +1,44 @@
+module ElmishStore.StoreApi
+
+open Feliz
+
+type IElmishStoreHooks<'Model> =
+ /// Provides a current snapshot of the store's state selected by the selector function.
+ /// NOTE: Selector returning value needs to be referentially stable.
+ abstract useSelector : selector: ('Model -> 'T) -> 'T
+ /// Provides a current snapshot of the store's state selected by the selector function.
+ /// The result of the selector function is memoized and compared with structural equality.
+ abstract useSelectorMemoized<'T when 'T : equality> : selector: ('Model -> 'T) -> 'T
+ /// Provides a current snapshot of the store's state selected by the selector function.
+ /// The result of the selector function is memoized and compared with isEqual function.
+ abstract useSelectorMemoizedWithCustomEquality : selector: ('Model -> 'T) -> isEqual: ('T -> 'T -> bool) -> 'T
+
+type IElmishStoreApi<'Model, 'Msg> =
+ inherit IElmishStoreHooks<'Model>
+
+ abstract Store : ElmishStore<'Model, 'Msg>
+
+
+let getElmishStoreApi (store: ElmishStore<'Model, 'Msg>) =
+ { new IElmishStoreApi<'Model, 'Msg> with
+ member _.Store = store
+
+ member _.useSelector(selector: 'Model -> 'T): 'T =
+ Hooks.useElmishStore store selector
+
+ member _.useSelectorMemoized<'T when 'T : equality> (selector: 'Model -> 'T) =
+ Hooks.useElmishStoreMemoized store selector
+
+ member _.useSelectorMemoizedWithCustomEquality<'T>
+ (selector: 'Model -> 'T)
+ (isEqual: 'T -> 'T -> bool): 'T
+ =
+ Hooks.useElmishStoreMemoizedWithCustomEquality store selector isEqual
+ }
+
+
+[]
+let useElmishStoreApi (store: ElmishStore<'Model, 'Msg>) =
+ React.useMemo (fun () ->
+ getElmishStoreApi store
+ , [| store |])
diff --git a/src/ElmishStore/UseSyncExternalStore.fs b/src/ElmishStore/UseSyncExternalStore.fs
index 2322eec..d375758 100644
--- a/src/ElmishStore/UseSyncExternalStore.fs
+++ b/src/ElmishStore/UseSyncExternalStore.fs
@@ -27,7 +27,6 @@ type internal ReactBindings =
) : 'a =
jsNative
- []
static member inline useSyncExternalStoreWithSelector
(
subscribe: UseSyncExternalStoreSubscribe,