-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Example: https://github.com/lumihq/purescript-react-basic/compare/michael/add-async-component?expand=1#diff-640d53ee0622b4db5f8d7fa4aed8f46eR44 Considering using React's suspend features for this but it might be too soon..
- Loading branch information
1 parent
7c19e84
commit 9999161
Showing
9 changed files
with
182 additions
and
6 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
output | ||
html/index.js | ||
package-lock.json | ||
node_modules |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
all: node_modules | ||
purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs' | ||
purs bundle -m Main --main Main output/*/*.js > output/bundle.js | ||
node_modules/.bin/browserify output/bundle.js -o html/index.js | ||
|
||
node_modules: | ||
npm install | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Async Counter Example | ||
|
||
## Building | ||
|
||
``` | ||
npm install | ||
make all | ||
``` | ||
|
||
This will compile the PureScript source files, bundle them, and use Browserify to combine PureScript and NPM sources into a single bundle. | ||
|
||
Then open `html/index.html` in your browser. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>react-basic example</title> | ||
</head> | ||
<body> | ||
<div id="container"></div> | ||
<script src="index.js"></script> | ||
</body> | ||
</html> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"dependencies": { | ||
"react": "16.6.0", | ||
"react-dom": "16.6.0" | ||
}, | ||
"devDependencies": { | ||
"browserify": "16.2.3" | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
module AsyncCounter where | ||
|
||
import Prelude | ||
|
||
import Effect.Aff (Milliseconds(..), delay) | ||
import Effect.Class (liftEffect) | ||
import Effect.Console (log) | ||
import React.Basic (Component, JSX, StateUpdate(..), capture_, createComponent, fragment, keyed, make) | ||
import React.Basic.Components.Async (asyncWithLoader) | ||
import React.Basic.DOM as R | ||
|
||
component :: Component Props | ||
component = createComponent "AsyncCounter" | ||
|
||
type Props = | ||
{ label :: String | ||
} | ||
|
||
data Action | ||
= Increment | ||
|
||
asyncCounter :: Props -> JSX | ||
asyncCounter = make component { initialState, update, render } | ||
where | ||
initialState = { counter: 0 } | ||
|
||
update self = case _ of | ||
Increment -> | ||
Update self.state { counter = self.state.counter + 1 } | ||
|
||
render self = | ||
fragment | ||
[ R.p_ [ R.text "Notes:" ] | ||
, R.ol_ | ||
[ R.li_ [ R.text "The two counts should never be out of sync" ] | ||
, R.li_ [ R.text "\"done\" should only be logged to the console once for any loading period (in-flight requests get cancelled as the next request starts)" ] | ||
] | ||
, R.button | ||
{ onClick: capture_ self Increment | ||
, children: [ R.text (self.props.label <> ": " <> show self.state.counter) ] | ||
} | ||
, R.text " " | ||
, keyed (show self.state.counter) $ | ||
asyncWithLoader (R.text "Loading...") do | ||
liftEffect $ log "start" | ||
delay $ Milliseconds 2000.0 | ||
liftEffect $ log "done" | ||
pure $ R.text $ "Done: " <> show self.state.counter | ||
] | ||
|
||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module Main where | ||
|
||
import Prelude | ||
|
||
import AsyncCounter (asyncCounter) | ||
import Data.Maybe (Maybe(..)) | ||
import Effect (Effect) | ||
import Effect.Exception (throw) | ||
import React.Basic.DOM (render) | ||
import Web.DOM.NonElementParentNode (getElementById) | ||
import Web.HTML (window) | ||
import Web.HTML.HTMLDocument (toNonElementParentNode) | ||
import Web.HTML.Window (document) | ||
|
||
main :: Effect Unit | ||
main = do | ||
container <- getElementById "container" =<< (map toNonElementParentNode $ document =<< window) | ||
case container of | ||
Nothing -> throw "Container element not found." | ||
Just c -> | ||
let app = asyncCounter { label: "Async Increment" } | ||
in render app c |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
module React.Basic.Components.Async | ||
( async | ||
, asyncWithLoader | ||
) where | ||
|
||
import Prelude | ||
|
||
import Data.Maybe (Maybe(..), fromMaybe) | ||
import Effect.Aff (Aff, Fiber, error, killFiber, launchAff, launchAff_) | ||
import Effect.Class (liftEffect) | ||
import React.Basic (Component, JSX, StateUpdate(..), createComponent, empty, make, send) | ||
|
||
component :: Component (Aff JSX) | ||
component = createComponent "Async" | ||
|
||
data FetchAction | ||
= ReplaceFiber (Fiber Unit) | ||
| UpdateJSX JSX | ||
|
||
async :: Aff JSX -> JSX | ||
async = asyncWithLoader empty | ||
|
||
asyncWithLoader :: JSX -> Aff JSX -> JSX | ||
asyncWithLoader loader = make component | ||
{ initialState | ||
, update | ||
, render | ||
, didMount: launch | ||
-- , didUpdate: No! Implementing `didUpdate` breaks the | ||
-- Aff/Component lifecycle relationship. | ||
-- To update the Aff over time, wrap this | ||
-- component with `keyed`. | ||
, willUnmount: cleanup | ||
} | ||
where | ||
initialState = | ||
{ jsx: Nothing | ||
, pendingFiber: pure unit | ||
} | ||
|
||
update { props, state } = case _ of | ||
ReplaceFiber newFiber -> | ||
UpdateAndSideEffects | ||
state { jsx = Nothing, pendingFiber = newFiber } | ||
\_ -> kill state.pendingFiber | ||
|
||
UpdateJSX jsx -> | ||
Update | ||
state { jsx = Just jsx } | ||
|
||
render self = | ||
fromMaybe loader self.state.jsx | ||
|
||
launch self = do | ||
fiber <- launchAff do | ||
jsx <- self.props | ||
liftEffect $ send self $ UpdateJSX jsx | ||
send self $ ReplaceFiber fiber | ||
|
||
cleanup self = | ||
kill self.state.pendingFiber | ||
|
||
kill = | ||
launchAff_ <<< killFiber (error "Cancelled") |