-
-
Save Zerim/6ff94ae1897d65bfbdae7279860bd43a to your computer and use it in GitHub Desktop.
| /* `action` and `state` types must be defined before the `let component` statement for type inference to work */ | |
| type action = | |
| | UpdateEmail string | |
| | UpdatePassword string; | |
| type state = { | |
| email: string, | |
| password: string | |
| }; | |
| /* Wrap the variant constructor in function so they may be composed */ | |
| let updateEmail email => UpdateEmail email; | |
| let updatePassword password => UpdatePassword password; | |
| let component = ReasonReact.reducerComponent "Signup"; | |
| /* Or could destructure here (i.e. `let handleSubmit _ {ReasonReact.state} => Js.log state`) */ | |
| let handleSubmit _ self => Js.log self.ReasonReact.state; | |
| let getEventTargetValue event :string => ( | |
| ReactDOMRe.domElementToObj ( | |
| ReactEventRe.Form.target event | |
| ) | |
| )##value; | |
| let make _children => { | |
| ...component, | |
| initialState: fun () => {email: "", password: ""}, | |
| reducer: fun action state => | |
| switch action { | |
| | UpdateEmail value => ReasonReact.Update {...state, email: value} | |
| | UpdatePassword value => ReasonReact.Update {...state, password: value} | |
| }, | |
| render: fun self => | |
| <div className="Login"> | |
| <div> <h2> (ReasonReact.stringToElement "Signup here") </h2> </div> | |
| /* Call self.handle to access the latest value of `self.ReasonReact.state` in the callback. */ | |
| <form onSubmit=(self.handle handleSubmit)> | |
| <input | |
| onChange=( | |
| self.ReasonReact.reduce (fun event => event |> getEventTargetValue |> updateEmail) | |
| ) | |
| placeholder="email" | |
| /> | |
| <input | |
| onChange=(self.reduce (fun event => event |> getEventTargetValue |> updatePassword)) | |
| placeholder="password" | |
| /> | |
| <input _type="submit" value="Register" /> | |
| </form> | |
| </div> | |
| }; |
I know one things that could be made more concise is having a UpdatePassword and UpdateEmail actions instead of having separate variants for the field type.
Looks great! Off the top of my head, you can design the form submit handler to be a bit more concise:
let handleSubmit state _ => Js.log state;
/* or let handleSubmit state _event => ... */
...
<form onSubmit=(handleSubmit self.state)>handleSubmit self.state will give you the state when the component was rendered - not necessarily the state when the button is clicked (guaranteed latest). If you want that you should use onSubmit=(self.handle handleSubmit) which will provide most up-to-date state and the form to handleSubmit.
Thanks for the feedback @yawaramin and @rickyvetter! Edits made.
I couldn't easily figure out how I should be typing self in the handleSubmit function by inspection (I used ReasonReact.self _ _ _). Is that idiomatic or should I be putting something else there? Seemed to compile/work okay...
Also I was wondering if you though the onChange callback could be made more concise through functional composition/ currying, but wasn't sure if that worked for Variant constructors.
Was thinking something like: onChange=(self.ReasonReact.reduce (compose UpdateEmail getEventTargetValue))
@Zerim - I'd use either of
let handleSubmit _ self => Js.log self.ReasonReact.state; or
let handleSubmit _ {ReasonReact.state} => Js.log state;
depending on actual usecase. You can explicitly type if you'd like, but self does have a lot of baggage to carry around.
Thanks @rickyvetter, forgot I could rely on type inference instead of explicitly annotating there.
Right now, the onSubmit just does a simple console.log for testing purposes, but in theory could be used for any side-effect. Any pointers to make this example more idiomatic would be appreciated!