Skip to content

Commit 042cf04

Browse files
committed
docs(getting-started): finishing the tutorial
1 parent 50981aa commit 042cf04

File tree

6 files changed

+136
-17
lines changed

6 files changed

+136
-17
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,6 @@ _esy
6969
# Docusaurus
7070
build
7171

72+
*.bs.js
73+
7274
.DS_STORE

website/docs/getting-started/SignUpForm_FormHook.res

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Form = ReForm.Make(FormFields)
1010

1111
@react.component
1212
let make = () => {
13+
// highlight-start
1314
let handleSubmit = ({state}: Form.onSubmitAPI) => {
1415
Js.log(state.values)
1516

@@ -28,5 +29,7 @@ let make = () => {
2829
(),
2930
)
3031

32+
// highlight-end
33+
3134
React.null
3235
}

website/docs/getting-started/SignUpForm_HandlingChanges.res

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ let make = () => {
3131
)
3232

3333
<Box display=[xs(#flex)] flexDirection=[xs(#column)] alignItems=[xs(#center)]>
34-
<Box maxW=[xs(320->#px)] width=[xs(100.0->#pct)]>
34+
<Box tag=#form maxW=[xs(320->#px)] width=[xs(100.0->#pct)]>
3535
<Typography tag=#h1 fontSize=[xs(24->#px)] fontWeight=[xs(#700)] mb=[xs(1)]>
3636
{"Sign up"->React.string}
3737
</Typography>

website/docs/getting-started/SignUpForm_Markup.res

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ let make = () => {
2525
~schema={
2626
open Form.Validation
2727

28-
Schema(string(~min=3, Name) + string(~min=8, Password) + email(~error=`Invalid email`, Email))
28+
Schema(string(~min=3, Name) + string(~min=8, Password) + email(~error="Invalid email", Email))
2929
},
3030
(),
3131
)
3232

3333
<Box display=[xs(#flex)] flexDirection=[xs(#column)] alignItems=[xs(#center)]>
34-
<Box maxW=[xs(320->#px)] width=[xs(100.0->#pct)]>
34+
<Box tag=#form maxW=[xs(320->#px)] width=[xs(100.0->#pct)]>
3535
<Typography tag=#h1 fontSize=[xs(24->#px)] fontWeight=[xs(#700)] mb=[xs(1)]>
3636
{"Sign up"->React.string}
3737
</Typography>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
open Ancestor.Default
2+
3+
module FormFields = %lenses(
4+
type state = {
5+
name: string,
6+
email: string,
7+
password: string,
8+
}
9+
)
10+
11+
module Form = ReForm.Make(FormFields)
12+
13+
@react.component
14+
let make = () => {
15+
let handleSubmit = ({state}: Form.onSubmitAPI) => {
16+
Js.log(state.values)
17+
18+
None
19+
}
20+
21+
let form = Form.use(
22+
~initialState={name: "", email: "", password: ""},
23+
~onSubmit=handleSubmit,
24+
~validationStrategy=OnDemand,
25+
~schema={
26+
open Form.Validation
27+
28+
Schema(string(~min=3, Name) + string(~min=8, Password) + email(~error="Invalid email", Email))
29+
},
30+
(),
31+
)
32+
33+
<Box display=[xs(#flex)] flexDirection=[xs(#column)] alignItems=[xs(#center)]>
34+
<Box tag=#form maxW=[xs(320->#px)] width=[xs(100.0->#pct)]>
35+
<Typography tag=#h1 fontSize=[xs(24->#px)] fontWeight=[xs(#700)] mb=[xs(1)]>
36+
{"Sign up"->React.string}
37+
</Typography>
38+
<Box>
39+
<Input
40+
placeholder="Your name"
41+
value={form.values.name}
42+
onChange={ReForm.Helpers.handleChange(form.handleChange(Name))}
43+
/>
44+
{switch Field(Name)->form.getFieldError {
45+
| None => React.null
46+
| Some(message) => <Input.Error> message </Input.Error>
47+
}}
48+
</Box>
49+
<Box mt=[xs(1)]>
50+
<Input
51+
placeholder="Your email"
52+
value={form.values.email}
53+
onChange={ReForm.Helpers.handleChange(form.handleChange(Email))}
54+
/>
55+
{switch Field(Email)->form.getFieldError {
56+
| None => React.null
57+
| Some(message) => <Input.Error> message </Input.Error>
58+
}}
59+
</Box>
60+
<Box mt=[xs(1)]>
61+
<Input
62+
type_="password"
63+
placeholder="Password"
64+
value={form.values.password}
65+
onChange={ReForm.Helpers.handleChange(form.handleChange(Password))}
66+
/>
67+
{switch Field(Password)->form.getFieldError {
68+
| None => React.null
69+
| Some(message) => <Input.Error> message </Input.Error>
70+
}}
71+
</Box>
72+
<Box mt=[xs(1)]>
73+
<Button
74+
onClick={e => {
75+
e->ReactEvent.Mouse.preventDefault
76+
form.submit()
77+
}}>
78+
{"Submit"->React.string}
79+
</Button>
80+
</Box>
81+
</Box>
82+
</Box>
83+
}

website/docs/getting-started/getting-started.md

+45-14
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import CodeBlock from '@theme/CodeBlock'
99
import HandlingChangesSource from '!!raw-loader!./SignUpForm_HandlingChanges.res'
1010
import MarkupSource from '!!raw-loader!./SignUpForm_Markup.res'
1111
import FormHookSource from '!!raw-loader!./SignUpForm_FormHook.res'
12+
import SubmitSource from '!!raw-loader!./SignUpForm_Submit.res'
1213
// Preview
1314
import { make as HandlingChangesPreview } from './SignUpForm_HandlingChanges.bs.js'
1415
import { make as MarkupPreview } from './SignUpForm_Markup.bs.js'
1516
import { make as FormHookPreview } from './SignUpForm_FormHook.bs.js'
17+
import { make as SubmitPreview } from './SignUpForm_Submit.bs.js'
1618
import { Preview } from '../__components'
1719

1820
After setting up `reform`, `reschema`, and `lenses-ppx` in the [previous section](/docs/installation), you're ready to create your first form. You can understand every
@@ -37,13 +39,13 @@ module FormFields = %lenses(
3739
The name of the record passed to `lenses-ppx` must be named as `state`.
3840
:::
3941

40-
You might be asking yourself: _"what this lenses-ppx is doing?"_ and it's kinda of magic, but it's a way to create "getters" and "setters" for the `state` record.
42+
You might be asking yourself: _"what this lenses-ppx is doing?"_ and it's kind of magic, but it's a way to create "getters" and "setters" for the `state` record.
4143

4244
After that, we have to create a new form using the `ReForm.Make` module functor.
4345
The module functor expects a lenses module which was created by
4446
`lenses-ppx` and returns a new form module. You can see the API reference of this module [here](/docs/reform-make).
4547

46-
```reason title="SignUpForm.res"
48+
```reason {9} title="SignUpForm.res"
4749
module FormFields = %lenses(
4850
type state = {
4951
name: string,
@@ -61,41 +63,70 @@ You can read more about module functors [here](https://rescript-lang.org/docs/ma
6163
### The `Form.use` hook
6264
ReForm provides a form hook and we're going to use it by passing some parameters like `schema`, an `onSubmit` function, `initialState`, etc.
6365

64-
<CodeBlock title="SignUpForm.res" className="language-reason"> {FormHookSource}</CodeBlock>
66+
<CodeBlock title="SignUpForm.res" className="language-reason"> {FormHookSource}</CodeBlock>
6567

6668
We can split this snippet in four parts:
67-
- 1. The `Form.use` hook calling: This is the hook provided by reform. It returns a `form` object that's typed as `Form.api` and you can read more about its api _here_.
69+
- 1. The `Form.use` hook calling: This is the hook provided by reform. It returns a `form` object that is typed as `Form.api` and you can read more about its api _here_.
6870
- 2. The `onSubmit` parameter: Just a function that will be called when you trigger the `form.submit` function.
6971
- 3. The `validationStrategy`: We're telling to reform which strategy of validation we want to use, in this case, we're using `OnDemand` which means that we'll trigger the validation **manually** using the `form` object.
70-
- 4. The `schema` parameter: It's a schema created using [ReSchema](https://github.com/rescriptbr/reschema). You can read more about the usage of _reschema with reform_ and its _official documentation_.
72+
- 4. The `schema` parameter: It's a schema created using [ReSchema](https://github.com/rescriptbr/reschema). You can read more about the usage of _reschema with reform_ and in its _official documentation_.
7173

7274
### Creating our form component
7375
We need a form to make everything works, so we're going to use a combination of inputs and button to create a simple sign up form:
7476
:::important
75-
For this tutorial, we created some local components (like `Input`, `Button`, `Input.Error`) just to make the markup more readable, but with the same API of native input and button (`onChange`, `value`, `onClick`, etc). Another components like `Box` or `Typography` are from [Ancestor](https://github.com/rescriptbr/reform) which is
77+
For this tutorial, we created some local components (like `Input`, `Button`, `Input.Error`) just to make the markup more readable, but with the same API of native (`onChange`, `value`, `onClick`, etc). Another components like `Box` or `Typography` are from [Ancestor](https://github.com/rescriptbr/reform) which is
7678
an UI library and is totally optional for this tutorial. Feel free to use pure html with or without css to create your own form.
7779
:::
78-
<CodeBlock title="SignUpForm.res" className="language-reason"> {MarkupSource}</CodeBlock>
80+
<CodeBlock metastring="{33-43}" title="SignUpForm.res" className="language-reason"> {MarkupSource}</CodeBlock>
81+
7982
<Preview>
8083
<MarkupPreview/>
8184
</Preview>
8285

8386

8487
### Integrating the form
85-
We created the `Form` module by combining `lenses-ppx`, `reform` and `reschema` and we also have a simple form component. Now, it's time to put everything to
86-
work together.
8788

88-
Different from libraries like [react-hook-form](https://react-hook-form.com/), ReForm doesn't use any kinda of magic with refs.
89+
We created the `Form` module by combining `lenses-ppx`, `reform` and `reschema` and we also have a simple form component. Now, it's time to make everything working together.
90+
91+
Different from libraries like [react-hook-form](https://react-hook-form.com/), ReForm doesn't use any kind of magic with refs.
8992
ReForm was created to be both deadly simple and to make forms sound good, leveraging ReScript's powerful typesytem.
9093
Even the schemas we use are nothing more than constructors built-in in the language itself.
9194

9295
We encourage you to handle every change in your inputs manually. Not just the changes, but also the conversion of values, like string to int or string to float.
93-
Could be more verbosive to do everything manually, but it's intentional and keep you in control of everything that happens with your forms.
96+
Might be more verbosive to do everything manually, but it's intentional and keep you in control of everything that happens with your forms.
9497

95-
The `form` record returned by reform has some fields like `handleChange` and `values` that we're going to use to make everything work.
96-
We're going to start by handling tha changes on the inputs:
98+
The `form` record returned by reform has some fields like `handleChange` and `values` that we're going to use to integrate the form module with our form component.
99+
We're going to start by handling the changes on the inputs:
97100

98-
<CodeBlock title="SignUpForm.res" className="language-reason"> {HandlingChangesSource}</CodeBlock>
101+
<CodeBlock metastring="{41-42,48-49,56-57,61-68}" title="SignUpForm.res" className="language-reason"> {HandlingChangesSource}</CodeBlock>
102+
103+
Also, we've added a simple block to display the form values. If you type something in any input, you can see the values changing:
99104
<Preview>
100105
<HandlingChangesPreview />
101106
</Preview>
107+
108+
But, we can just type and see the values, if you click on the submit button, nothing happens, no error messages, no console.log, etc.
109+
To make everything works, we still have to do two things: trigger the `form.submit` function and render the validation errors (when we got an error) using then`form.getFieldError` function:
110+
111+
<CodeBlock metastring="{55-58,44-47,67-70,74-77}" title="SignUpForm.res" className="language-reason"> {SubmitSource}</CodeBlock>
112+
113+
Now, when we click on the submit button without fill the form (or filling with invalid values), we can see the error message for each field.
114+
Also, if we open the browser console and fill all fields correctly, we can see the result of the form submission on the console.
115+
116+
<Preview>
117+
<SubmitPreview />
118+
</Preview>
119+
120+
<br/>
121+
122+
123+
### Disclaimers
124+
125+
There are some disclaimers about this part of the tutorial:
126+
127+
- The first one, is about the handling of our `handleSubmit` function. If you click on the submit button without filling the fields, the function
128+
will not be triggered. That's the expected behavior. The `onSubmit` function will be triggered when the form is valid. If you need to handle
129+
a function on the submit and there are invalid fields, you can use the `onSubmitFail` parameter. You can read more about this **here**.
130+
- Because we're passing `OnDemand` to the `validationStrategy` parameter, we have to call the form validation **manually** using a function like `form.validateForm` or just call
131+
call the `form.submit` function (like we did) that triggers the form validation automatically. If you need to trigger the validation on every change, you can use `OnChange` as a validation strategy.
132+
You can read more about validation strategies **here**.

0 commit comments

Comments
 (0)