Skip to content

Hooks #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
"dependencies": {
"purescript-react-dom": "^6.0.0",
"purescript-console": "^4.0.0",
"purescript-react": "^6.0.0",
"purescript-web-html": "^1.0.0"
"purescript-react": "hooks",
"purescript-web-html": "^1.0.0",
"purescript-free": "^5.1.0"
},
"resolutions": {
"purescript-react": "hooks"
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"webpack-dev-server": "DEBUG=* webpack-dev-server --mode development --progress --inline --hot"
},
"dependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0"
"react": "^16.7.0-alpha.2",
"react-dom": "^16.7.0-alpha.2"
},
"devDependencies": {
"pscid": "^2.0.2",
Expand Down
75 changes: 75 additions & 0 deletions src/Example.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module Example where

import Prelude

import Data.Array (snoc, modifyAt, elemIndex)
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Tuple (Tuple(..))

import React as React
import React.Hook (Hook)
import React.Hook as Hook

import Example.TodoList (todoList)
import Example.Types (Todo(..), TodoStatus(..))

data Action
= Add Todo
| Edit Todo
| Done Todo
| Clear Todo

example :: { } -> Hook React.ReactElement
example _ =
React.createHookLeafElement todoList <$> hook
where
hook = do
Tuple state dispatch <- Hook.useReducer reducer initialState

let
inputs = Just [ Hook.hookInput dispatch ]

onAdd <- Hook.useCallback (Hook.dispatch dispatch <<< Add) inputs

onEdit <- Hook.useCallback (Hook.dispatch dispatch <<< Edit) inputs

onDone <- Hook.useCallback (Hook.dispatch dispatch <<< Done) inputs

onClear <- Hook.useCallback (Hook.dispatch dispatch <<< Clear) inputs

pure { todo: state.todo
, todos: state.todos
, onAdd
, onEdit
, onDone
, onClear
}
where
initialState =
{ todo: Nothing
, todos: [ ]
}

reducer state =
case _ of
Add todo -> state
{ todo = Nothing
, todos = snoc state.todos todo
}

Edit todo -> state
{ todo = Just todo
}

Done todo -> state
{ todos = setStatus todo TodoDone
}

Clear todo -> state
{ todos = setStatus todo TodoCleared
}
where
setStatus todo status = fromMaybe state.todos $ do
i <- elemIndex todo state.todos

modifyAt i (\(Todo a) -> Todo a { status = status }) state.todos
11 changes: 11 additions & 0 deletions src/Example/TodoContext.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Example.TodoContext where

import Data.Maybe (Maybe(..))

import React.Context (Context)
import React.Context as Context

type TodoContext = Context { backgroundColor :: String }

todoContext :: TodoContext
todoContext = Context.createContext { backgroundColor: "red" } Nothing
98 changes: 60 additions & 38 deletions src/Example/TodoForm.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@ module Example.TodoForm where

import Prelude

import Effect (Effect)
import Data.Maybe (Maybe(..), maybe, isNothing)

import Data.Maybe (Maybe, maybe, isNothing)
import Effect (Effect)

import React as React
import React.Hook (Hook)
import React.Hook as Hook
import React.Ref as Ref
import React.SyntheticEvent as Event
import React.DOM as DOM
import React.DOM.Props as Props

import Web.HTML.HTMLElement as HTML

import Unsafe.Coerce (unsafeCoerce)

import Example.TodoContext as TodoContext
import Example.Types (Todo(..), TodoStatus(..))

type TodoFormProps
Expand All @@ -21,45 +27,61 @@ type TodoFormProps
, onAdd :: Todo -> Effect Unit
}

todoFormClass :: React.ReactClass TodoFormProps
todoFormClass = React.component "TodoForm" component
todoForm :: TodoFormProps -> Hook React.ReactElement
todoForm
{ todo
, onEdit
, onAdd
} =
render <$> hook
where
component this =
pure { state: {}
, render: render <$> React.getProps this
}
hook = do
context <- Hook.useContext TodoContext.todoContext

ref <- Hook.useRef Nothing

pure { ref, context }

render
{ ref
, context:
{ backgroundColor
}
} =
DOM.form
[ Props.onSubmit onSubmit ]
[ DOM.input
[ Props._type "text"
, Props.value value
, Props.ref ref
, Props.onChange onChange
, Props.style { backgroundColor }
]
, DOM.button
[ Props._type "submit"
, Props.disabled isDisabled
]
[ DOM.text "Add" ]
]
where
render
{ todo
, onEdit
, onAdd
} =
DOM.form
[ Props.onSubmit onSubmit ]
[ DOM.input
[ Props._type "text"
, Props.value value
, Props.onChange onChange
]
, DOM.button
[ Props._type "submit"
, Props.disabled isDisabled
]
[ DOM.text "Add" ]
]
where
value = maybe "" (\(Todo { text }) -> text) todo
value = maybe "" (\(Todo { text }) -> text) todo

isDisabled = isNothing todo

onSubmit event = do
Event.preventDefault event

isDisabled = isNothing todo
maybe (pure unit) onAdd todo

onSubmit event = do
Event.preventDefault event
domRef <- Ref.getRef ref

maybe (pure unit) onAdd todo
maybe (pure unit) (HTML.blur <<< unsafeCoerce) domRef

onChange event = onEdit $
maybe (Todo { text, status: TodoPending })
(\(Todo todo_) -> Todo todo_ { text = text })
todo
where
text = (unsafeCoerce event).target.value
pure unit

onChange event = onEdit $
maybe (Todo { text, status: TodoPending })
(\(Todo todo_) -> Todo todo_ { text = text })
todo
where
text = (unsafeCoerce event).target.value
41 changes: 25 additions & 16 deletions src/Example/TodoItem.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,36 @@ module Example.TodoItem where
import Prelude

import React as React
import React.Context as Context
import React.Hook (Hook)
import React.DOM as DOM
import React.DOM.Props as Props

import Example.TodoContext as TodoContext
import Example.Types (Todo(..), TodoStatus(..))

type TodoItemProps = { todo :: Todo }

todoItemClass :: React.ReactClass TodoItemProps
todoItemClass = React.component "TodoItem" component
todoItem :: TodoItemProps -> Hook React.ReactElement
todoItem
{ todo: Todo
{ text
, status
}
} = pure $
React.createRenderPropsElement consumer { } $ \{ backgroundColor } ->
DOM.div
[ Props.style
{ textDecoration
, backgroundColor
}
]
[ React.toElement text ]
where
component this =
pure { state: {}
, render: render <$> React.getProps this
}
where
render { todo: Todo { text, status } } =
DOM.div
[ Props.style { textDecoration } ]
[ React.toElement text ]
where
textDecoration =
case status of
TodoDone -> "line-through"
_ -> "none"
consumer = Context.getConsumer TodoContext.todoContext

textDecoration =
case status of
TodoDone -> "line-through"
_ -> "none"

Loading