Skip to content

Commit 429f41d

Browse files
committed
React-basic 10
1 parent a76aa48 commit 429f41d

File tree

7 files changed

+384
-402
lines changed

7 files changed

+384
-402
lines changed

README.md

+10-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# react-basic-hooks [![CircleCI](https://circleci.com/gh/spicydonuts/purescript-react-basic-hooks.svg?style=svg)](https://circleci.com/gh/spicydonuts/purescript-react-basic-hooks)
22

3-
This is library adds React hooks to [react-basic](https://github.com/lumihq/purescript-react-basic).
3+
`react-basic-hooks` adds React hook support to [react-basic](https://github.com/lumihq/purescript-react-basic)!
44

5-
_Warning:_ This API relies on recent React versions (>= 16.8.0).
5+
_Note:_ This API relies on recent React versions (>= 16.8.0).
66
For more info on hooks, see [React's documentation](https://reactjs.org/docs/hooks-intro.html).
77

8-
I recommend using PureScript's new "qualified do" syntax while using this library (it's used in the examples, the `React.do` bits).
8+
I recommend using PureScript's "qualified do" syntax while using this library (it's used in the examples, the `React.do` bits).
99
It became available in the `0.12.2` compiler release.
1010

1111
This library provides the `React.Basic.Hooks` module, which can completely replace the `React.Basic` module.
@@ -20,10 +20,13 @@ mkCounter = do
2020
component "Counter" \props -> React.do
2121
counter /\ setCounter <- useState 0
2222
23-
React.pure $ R.button
24-
{ onClick: handler_ $ setCounter (_ + 1)
25-
, children: [ R.text $ "Increment: " <> show counter ]
26-
}
23+
pure
24+
$ R.button
25+
{ onClick: handler_ do
26+
setCounter (_ + 1)
27+
, children:
28+
[ R.text $ "Increment: " <> show counter ]
29+
}
2730
```
2831

2932
More examples:
@@ -36,7 +39,3 @@ More examples:
3639
- [A Todo App](./examples/todo-app/src/TodoApp.purs) (components, inputs, state)
3740
- [Context](./examples/context/src/Context.purs) (creating and consuming React context)
3841
- [Aff helper](./examples/aff/src/AffEx.purs) (async state management)
39-
40-
_A note on Refs:_ The `Ref` type is useful for all kinds of state (anything which shouldn't trigger a render when changed), particularly references to DOM nodes as in the example.
41-
Unfortunately, while this module remains a small extension to the existing react-basic library it won't be possible to pass a `ref` prop to the native DOM components from `React.Basic.DOM`.
42-
In the meantime, use `element (unsafeCreateDOMComponent "div") { ref: elementRef }`.

bower.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"purescript-prelude": "^4.1.0",
1616
"purescript-console": "^4.2.0",
1717
"purescript-effect": "^2.0.0",
18-
"purescript-react-basic": "^8.0.0 || ^9.0.0",
18+
"purescript-react-basic": "^10.0.0",
1919
"purescript-indexed-monad": "^1.0.0",
2020
"purescript-unsafe-reference": "^3.0.1",
2121
"purescript-aff": "^5.1.1"

examples/aff/src/AffEx.purs

+55-51
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
module AffEx where
22

33
import Prelude
4-
54
import Data.Either (either)
65
import Data.Maybe (Maybe(..), maybe)
76
import Effect.Aff (Aff, Milliseconds(..), delay, error, message, throwError)
@@ -15,19 +14,18 @@ mkAffEx :: CreateComponent {}
1514
mkAffEx = do
1615
-- A component for fetching and rendering a Cat entity.
1716
catDetails <- mkCatDetails
18-
1917
component "AffEx" \props -> React.do
2018
catKey /\ catChooser <- useCatKeyChooser
21-
22-
pure $ R.div
23-
{ style: R.css { display: "flex", flexFlow: "column" }
24-
, children:
19+
pure
20+
$ R.div
21+
{ style: R.css { display: "flex", flexFlow: "column" }
22+
, children:
2523
[ R.h2_ [ R.text "Cat chooser" ]
2624
, R.p_
27-
[ R.text $
28-
"Select a key to fetch! If you get bored (how would you even!?) " <>
29-
"try holding your arrow keys to select really fast! The result " <>
30-
"always matches the chosen key."
25+
[ R.text
26+
$ "Select a key to fetch! If you get bored (how would you even!?) "
27+
<> "try holding your arrow keys to select really fast! The result "
28+
<> "always matches the chosen key."
3129
]
3230
, catChooser
3331
, R.p_
@@ -36,60 +34,63 @@ mkAffEx = do
3634
Just k -> element catDetails { catKey: k }
3735
]
3836
]
39-
}
37+
}
4038
where
41-
-- This hook packages up some interactive UI and the current
42-
-- selection the user has made via that UI.
43-
useCatKeyChooser :: Hook _ ((Maybe (Key Cat)) /\ JSX)
44-
useCatKeyChooser = React.do
45-
catKey /\ setCatKey <- useState Nothing
46-
let
47-
catChoice key =
48-
R.label_
49-
[ R.input
50-
{ type: "radio"
51-
, name: "cat-key"
52-
, checked: Just key == catKey
53-
, onChange: handler_ do
54-
setCatKey \_ -> Just key
55-
}
56-
, R.text $ showCatKey key
57-
]
58-
59-
showCatKey :: Key Cat -> String
60-
showCatKey (Key key) = "Cat " <> key
39+
-- This hook packages up some interactive UI and the current
40+
-- selection the user has made via that UI.
41+
useCatKeyChooser :: Hook _ ((Maybe (Key Cat)) /\ JSX)
42+
useCatKeyChooser = React.do
43+
catKey /\ setCatKey <- useState Nothing
44+
let
45+
catChoice key =
46+
R.label_
47+
[ R.input
48+
{ type: "radio"
49+
, name: "cat-key"
50+
, checked: Just key == catKey
51+
, onChange:
52+
handler_ do
53+
setCatKey \_ -> Just key
54+
}
55+
, R.text $ showCatKey key
56+
]
6157

62-
pure $ catKey /\ fragment
63-
[ catChoice $ Key "abc"
64-
, catChoice $ Key "def"
65-
, catChoice $ Key "xyz"
66-
]
67-
68-
-- Hooks can't be used conditionally but components can!
69-
-- Not needing to deal with a `Maybe` key simplifies this
70-
-- compoennt a bit.
71-
mkCatDetails :: CreateComponent { catKey :: Key Cat }
72-
mkCatDetails = do
73-
component "CatDetails" \{ catKey } -> React.do
74-
cat <- useAff catKey $ fetch catKey
75-
pure $ R.text $
76-
maybe "Loading..." (either message showCat) cat
77-
where
78-
showCat (Cat { name }) = "A cat named " <> name
58+
showCatKey :: Key Cat -> String
59+
showCatKey (Key key) = "Cat " <> key
60+
pure $ catKey
61+
/\ fragment
62+
[ catChoice $ Key "abc"
63+
, catChoice $ Key "def"
64+
, catChoice $ Key "ghi"
65+
, catChoice $ Key "xyz"
66+
]
7967

68+
-- Hooks can't be used conditionally but components can!
69+
-- Not needing to deal with a `Maybe` key simplifies this
70+
-- compoennt a bit.
71+
mkCatDetails :: CreateComponent { catKey :: Key Cat }
72+
mkCatDetails = do
73+
component "CatDetails" \{ catKey } -> React.do
74+
cat <- useAff catKey $ fetch catKey
75+
pure $ R.text
76+
$ maybe "Loading..." (either message showCat) cat
77+
where
78+
showCat (Cat { name }) = "A cat named " <> name
8079

8180
-- Typed keys are a great way to tie entity-specific behavior
8281
-- to an ID. We can use this phantom type to write a class
8382
-- for generic, type-safe data fetching.
84-
newtype Key entity = Key String
83+
newtype Key entity
84+
= Key String
85+
8586
derive instance eqKey :: Eq (Key entity)
8687

8788
class Fetch entity where
8889
fetch :: Key entity -> Aff entity
8990

90-
9191
-- An example entity
92-
newtype Cat = Cat { name :: String }
92+
newtype Cat
93+
= Cat { name :: String }
9394

9495
instance fetchCat :: Fetch Cat where
9596
fetch = case _ of
@@ -99,6 +100,9 @@ instance fetchCat :: Fetch Cat where
99100
Key "def" -> do
100101
delay $ Milliseconds 600.0
101102
pure $ Cat { name: "Maxi" }
103+
Key "ghi" -> do
104+
delay $ Milliseconds 900.0
105+
pure $ Cat { name: "Chloe" }
102106
_ -> do
103107
delay $ Milliseconds 900.0
104108
throwError $ error "Cat not found (intended example behavior 😅)"

examples/context/src/Context.purs

+30-38
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,48 @@
11
module Context where
22

33
import Prelude
4-
5-
import Data.Maybe (Maybe(..))
64
import Effect (Effect)
75
import React.Basic.DOM as R
86
import React.Basic.Events (handler_)
9-
import React.Basic.Hooks (Context, CreateComponent, JSX, type (/\), component, contextProvider, createContext, element, fragment, useContext, useState, (/\))
7+
import React.Basic.Hooks (type (/\), CreateComponent, JSX, ReactContext, component, createContext, element, provider, useContext, useState, (/\))
108
import React.Basic.Hooks as React
119

1210
mkContext :: CreateComponent {}
1311
mkContext = do
14-
15-
counterContext <- createContext
12+
counterContext <- createContext (0 /\ pure unit)
1613
store <- mkStore counterContext
1714
counter <- mkCounter counterContext
18-
1915
component "Context" \props -> React.do
20-
21-
pure $ element store
22-
{ children:
23-
[ element counter {}
24-
, element counter {}
25-
, element counter {}
26-
]
27-
}
28-
29-
mkStore
30-
:: Context (Int /\ (Effect Unit))
31-
-> CreateComponent { children :: Array JSX }
16+
pure
17+
$ element store
18+
{ children:
19+
[ element counter {}
20+
, element counter {}
21+
, element counter {}
22+
]
23+
}
24+
25+
mkStore ::
26+
ReactContext (Int /\ (Effect Unit)) ->
27+
CreateComponent { children :: Array JSX }
3228
mkStore context = do
3329
component "Store" \{ children } -> React.do
3430
counter /\ setCounter <- useState 0
35-
let increment = setCounter (_ + 1)
36-
pure $
37-
contextProvider context
38-
(counter /\ increment)
39-
(fragment children)
40-
41-
mkCounter
42-
:: Context (Int /\ (Effect Unit))
43-
-> CreateComponent {}
31+
let
32+
increment = setCounter (_ + 1)
33+
pure
34+
$ provider context
35+
(counter /\ increment)
36+
children
37+
38+
mkCounter ::
39+
ReactContext (Int /\ (Effect Unit)) ->
40+
CreateComponent {}
4441
mkCounter counterContext = do
4542
component "Counter" \props -> React.do
46-
mCounter <- useContext counterContext
47-
48-
case mCounter of
49-
Nothing -> do
50-
pure $ R.text "no counter value found"
51-
Just (counter /\ increment) -> do
52-
pure $
53-
R.button
54-
{ onClick: handler_ increment
55-
, children: [ R.text $ "Increment: " <> show counter ]
56-
}
43+
counter /\ increment <- useContext counterContext
44+
pure
45+
$ R.button
46+
{ onClick: handler_ increment
47+
, children: [ R.text $ "Increment: " <> show counter ]
48+
}

0 commit comments

Comments
 (0)