From f889de1bfc107015a419d6c64fa551a07c66dbe0 Mon Sep 17 00:00:00 2001 From: katsujukou <74475348+katsujukou@users.noreply.github.com> Date: Sun, 8 Aug 2021 06:57:39 +0900 Subject: [PATCH] Add UseSelector hook (#3) --- README.md | 20 ++++++++++++++ example/basic-hooks/Basic/Counter.purs | 30 ++++++++++++++++++++ example/basic-hooks/Basic/Main.purs | 17 ++++++++++++ example/basic-hooks/Basic/Store.purs | 17 ++++++++++++ example/basic-hooks/README.md | 3 ++ example/basic-hooks/index.html | 17 ++++++++++++ package.json | 3 +- spago.dhall | 2 ++ src/Halogen/Store/Hooks/UseSelector.purs | 35 ++++++++++++++++++++++++ src/Halogen/Store/Monad.purs | 6 ++++ 10 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 example/basic-hooks/Basic/Counter.purs create mode 100644 example/basic-hooks/Basic/Main.purs create mode 100644 example/basic-hooks/Basic/Store.purs create mode 100644 example/basic-hooks/README.md create mode 100644 example/basic-hooks/index.html create mode 100644 src/Halogen/Store/Hooks/UseSelector.purs diff --git a/README.md b/README.md index 01dcca7..2320c30 100644 --- a/README.md +++ b/README.md @@ -198,3 +198,23 @@ main = launchAff_ do root <- runStoreT BS.initialStore BS.reduce Counter.component runUI root unit body ``` + +### Using store with hooks + +If you want to write your component with [Halogen Hooks library](https://github.com/thomashoneyman/purescript-halogen-hooks) ,then you can use `useSelector` hook to access store. It takes selector and return the part of current store retrieved via given selector. + +```purs +import Halogen.Hooks as Hooks +import Halogen.Store.Hooks (useSelector) +import Halogen.Store.Select (selectAll) + +component :: forall q i o m + . MonadStore BS.Action BS.Store m + => H.Component q i o m +component = Hooks.component \_ _ -> Hooks.do + ctx <- useSelector selectAll + Hooks.pure do + ... +``` + +Unlike the case with connect, though, context returned by `useSelector` hook has type `Maybe store`, because the hook does not have access to store before it has been initialized. \ No newline at end of file diff --git a/example/basic-hooks/Basic/Counter.purs b/example/basic-hooks/Basic/Counter.purs new file mode 100644 index 0000000..90acf51 --- /dev/null +++ b/example/basic-hooks/Basic/Counter.purs @@ -0,0 +1,30 @@ +module Hooks.Counter where + +import Prelude + +import Basic.Store as BS +import Data.Maybe (fromMaybe) +import Halogen as H +import Halogen.HTML as HH +import Halogen.HTML.Events as HE +import Halogen.Hooks as Hooks +import Halogen.Store.Hooks.UseSelector (useSelector) +import Halogen.Store.Monad (class MonadStore, updateStore) +import Halogen.Store.Select (selectEq) + +component :: forall q i o m + . MonadStore BS.Action BS.Store m + => H.Component q i o m +component = Hooks.component \_ _ -> Hooks.do + count <- useSelector $ selectEq _.count + Hooks.pure do + let cnt = fromMaybe 0 count + HH.div_ + [ HH.button + [ HE.onClick \_ -> updateStore BS.Increment ] + [ HH.text "Increment"] + , HH.text $ " Count: " <> show cnt <> " " + , HH.button + [ HE.onClick \_ -> updateStore BS.Decrement ] + [ HH.text "Decrement" ] + ] \ No newline at end of file diff --git a/example/basic-hooks/Basic/Main.purs b/example/basic-hooks/Basic/Main.purs new file mode 100644 index 0000000..293ac82 --- /dev/null +++ b/example/basic-hooks/Basic/Main.purs @@ -0,0 +1,17 @@ +module Hooks.Main where + +import Prelude + +import Basic.Counter as Counter +import Basic.Store as BS +import Effect (Effect) +import Effect.Aff (launchAff_) +import Halogen.Aff as HA +import Halogen.Store.Monad (runStoreT) +import Halogen.VDom.Driver (runUI) + +main :: Effect Unit +main = launchAff_ do + body <- HA.awaitBody + root <- runStoreT BS.initialStore BS.reduce Counter.component + runUI root unit body diff --git a/example/basic-hooks/Basic/Store.purs b/example/basic-hooks/Basic/Store.purs new file mode 100644 index 0000000..14b5190 --- /dev/null +++ b/example/basic-hooks/Basic/Store.purs @@ -0,0 +1,17 @@ +module Hooks.Store where + +import Prelude + +type Store = { count :: Int } + +initialStore :: Store +initialStore = { count: 0 } + +data Action + = Increment + | Decrement + +reduce :: Store -> Action -> Store +reduce store = case _ of + Increment -> store { count = store.count + 1 } + Decrement -> store { count = store.count - 1 } diff --git a/example/basic-hooks/README.md b/example/basic-hooks/README.md new file mode 100644 index 0000000..c1fa0aa --- /dev/null +++ b/example/basic-hooks/README.md @@ -0,0 +1,3 @@ +# Hooks Example + +The basic-hooks example is yet another alternative to the basic example. It demonstrates how to access a small store from a single component (a counter) using hooks functionality (`useSeletor`) instead of stateful component. \ No newline at end of file diff --git a/example/basic-hooks/index.html b/example/basic-hooks/index.html new file mode 100644 index 0000000..844b31a --- /dev/null +++ b/example/basic-hooks/index.html @@ -0,0 +1,17 @@ + + +
+