From a973d7f0b421aef0baa003f9bb7428d753dc2ae7 Mon Sep 17 00:00:00 2001 From: ArtemyB Date: Fri, 9 Aug 2024 16:26:32 +0300 Subject: [PATCH 1/2] refactor: move hooks from type to module - Introduce `Hooks` module with all the hooks moved there instead of being defined in the `React` type. This way, the generated JS is cleaner because module function names aren't mangled. - Move `React` inline type extensions to a separate "Extensions" file. - Remove `Hook` attributes from inline functions for their irrelevance. --- src/ElmishStore/ElmishStore.fsproj | 1 + src/ElmishStore/Extensions.fs | 23 +++++++++ src/ElmishStore/Hooks.fs | 66 ++++++++++++------------- src/ElmishStore/UseSyncExternalStore.fs | 1 - 4 files changed, 56 insertions(+), 35 deletions(-) create mode 100644 src/ElmishStore/Extensions.fs diff --git a/src/ElmishStore/ElmishStore.fsproj b/src/ElmishStore/ElmishStore.fsproj index 19c0958..2f9202f 100644 --- a/src/ElmishStore/ElmishStore.fsproj +++ b/src/ElmishStore/ElmishStore.fsproj @@ -22,6 +22,7 @@ + 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/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, From 9be2b445741c7dfa8c80d421a5938943d6b74857 Mon Sep 17 00:00:00 2001 From: ArtemyB Date: Fri, 9 Aug 2024 16:30:41 +0300 Subject: [PATCH 2/2] build: update project configuration - Target .NET 6 instead of .NET 8 to relax package requirements. - Relax "FSharp.Core" dependency to v6. - Introduce "Fable.Package.SDK" package to facilitate project configuration for Fable. - Bump package version to 0.2.1. - [Example] Update "Feliz" to v2.8.0, update Fable to v4.7.0. --- .config/dotnet-tools.json | 2 +- .../ElmishStore.Example.fsproj | 1 + src/ElmishStore/ElmishStore.fsproj | 73 ++++++++++--------- 3 files changed, 41 insertions(+), 35 deletions(-) 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..886fe66 100644 --- a/src/ElmishStore.Example/ElmishStore.Example.fsproj +++ b/src/ElmishStore.Example/ElmishStore.Example.fsproj @@ -31,6 +31,7 @@ + diff --git a/src/ElmishStore/ElmishStore.fsproj b/src/ElmishStore/ElmishStore.fsproj index 2f9202f..27fa7e4 100644 --- a/src/ElmishStore/ElmishStore.fsproj +++ b/src/ElmishStore/ElmishStore.fsproj @@ -1,36 +1,41 @@ - + - - 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 - - - - - - - - - - - - - - - - - - - - - + + 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.2.1 + net6.0 + readme.md + https://github.com/SelectViewData/elmish-store + git + MIT + + + fable-javascript + library + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file