Created
January 17, 2022 12:50
-
-
Save ribeirotomas1904/24856c3c85baf4c470c965d8634b02e8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// fsharplint:disable MemberNames | |
namespace Feliz.UsePersist | |
open Feliz | |
open Browser.WebStorage | |
open Thoth.Json | |
[<RequireQualifiedAccess>] | |
type StorageOption = | |
| Local | |
| Session | |
[<AutoOpen>] | |
module ReactHookExtensions = | |
let inline private getStorage (storageOption: StorageOption option) : Browser.Types.Storage = | |
match storageOption with | |
| None | |
| Some StorageOption.Local -> localStorage | |
| Some StorageOption.Session -> sessionStorage | |
let inline private getInitial (storage: Browser.Types.Storage) (key: string) (initial: 'a) = | |
storage.getItem key | |
|> Decode.Auto.fromString | |
|> function | |
| Ok item -> item | |
| Error _ -> initial | |
let inline private getInitializer (storage: Browser.Types.Storage) (key: string) (initializer: unit -> 'a) = | |
storage.getItem key | |
|> Decode.Auto.fromString | |
|> function | |
| Ok item -> fun () -> item | |
| Error _ -> initializer | |
// Work on a better name | |
// Should i use [<Hook>] on inlined functions that deal with state? | |
// Should i annotate just the minimum required types? | |
let inline private stateSubscriber (storage: Browser.Types.Storage) (key: string) (state: 'a) : unit = | |
React.useEffect ( | |
(fun () -> | |
Encode.Auto.toString (0, state) | |
|> fun x -> storage.setItem (key, x)), | |
[| box state |] | |
) | |
type React with | |
// Should i use [<Hook>] on inlined functions that deal with state? | |
[<Hook>] | |
static member inline usePersist(key: string, initial: 'a, ?storageOption: StorageOption) : 'a * ('a -> unit) = | |
let storage = getStorage storageOption | |
let initial': 'a = getInitial storage key initial | |
let (state, setState) = React.useState initial' | |
stateSubscriber storage key state | |
state, setState | |
[<Hook>] | |
static member inline usePersist | |
( | |
key: string, | |
initializer: unit -> 'a, | |
?storageOption: StorageOption | |
) : 'a * ('a -> unit) = | |
let storage = getStorage storageOption | |
let initializer': unit -> 'a = getInitializer storage key initializer | |
let (state, setState) = React.useState initializer' | |
stateSubscriber storage key state | |
state, setState | |
[<Hook>] | |
static member inline usePersistWithUpdater | |
( | |
key: string, | |
initial: 'a, | |
?storageOption: StorageOption | |
) : 'a * (('a -> 'a) -> unit) = | |
let storage = getStorage storageOption | |
let initial': 'a = getInitial storage key initial | |
let (state, setState) = React.useStateWithUpdater initial' | |
stateSubscriber storage key state | |
state, setState | |
// Error because React.useStateWithUpdater cannot use lazy initialization yet | |
// [<Hook>] | |
// static member inline usePersistWithUpdater | |
// ( | |
// key: string, | |
// initializer: unit -> 'a, | |
// ?storageOption: StorageOption | |
// ) : 'a * (('a -> 'a) -> unit) = | |
// let storage = getStorage storageOption | |
// let initializer': unit -> 'a = getInitializer storage key initializer | |
// let (state, setState) = | |
// React.useStateWithUpdater<'a> initializer' | |
// stateSubscriber storage key state | |
// state, setState |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment