Skip to content

Commit a44ec37

Browse files
authored
Add useWatch hook (#12)
* add useWatch hook * change log
1 parent f5c5cf7 commit a44ec37

File tree

7 files changed

+230
-3
lines changed

7 files changed

+230
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# v0.0.8 (unrelease)
22

3+
- Add `useWatch` hook
4+
35
# v0.0.7
46

57
- Add `getValues` to `useForm` hook

doc/transformation.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ module ControllerOfInputs = {
8888
) => React.element = "Controller"
8989
}
9090
91+
//useWatch
92+
type useWatchParamsOfInputs = {
93+
name: variantOfInputs,
94+
control: controlOfInputs=?,
95+
defaultValue: valueOfInputs=?,
96+
disabled: bool=?,
97+
exact: bool=?,
98+
}
99+
@module("react-hook-form")
100+
external useWatchOfInputs: useWatchParamsOfInputs => option<valueOfInputs>
101+
91102
// useFieldArray
92103
type rec useFieldArrayReturnOfInputsCart = {
93104
fields: array<itemWithId>,

src/ppx/signature.ml

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,78 @@ let map_type_decl
599599
]))
600600
in
601601

602+
(* type useWatchParamsOfInputs = {
603+
name: variantOfInputs,
604+
control: controlOfInputs=?,
605+
defaultValue: valueOfInputs=?,
606+
disabled: bool=?,
607+
exact: bool=?,
608+
} *)
602609
let type_decls4 =
610+
Sig.type_ Recursive
611+
[
612+
Type.mk
613+
(mkloc ("useWatchParamsOf" ^ capitalize record_name) ptype_loc)
614+
~priv:Public
615+
~kind:
616+
(Ptype_record
617+
[
618+
Type.field ~mut:Immutable (mknoloc "name")
619+
(Typ.constr
620+
(lid @@ "variantOf" ^ capitalize record_name)
621+
[]);
622+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
623+
(mknoloc "control")
624+
(Typ.constr ~attrs:[ attr_named_arg ]
625+
(lid @@ "controlOf" ^ capitalize record_name)
626+
[]);
627+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
628+
(mknoloc "defaultValue")
629+
(Typ.constr
630+
(lid @@ "valuesOf" ^ capitalize record_name)
631+
[]);
632+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
633+
(mknoloc "disabled")
634+
(Typ.constr (lid "bool") []);
635+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
636+
(mknoloc "exact")
637+
(Typ.constr (lid "bool") []);
638+
]);
639+
]
640+
in
641+
642+
(* @module("react-hook-form")
643+
external useWatchOfInputs: useWatchParamsOfInputs => option<valuesOfInputs> = "useWatch" *)
644+
let primitive_use_watch =
645+
Sig.value
646+
(Val.mk
647+
~attrs:
648+
[
649+
Attr.mk (mknoloc "module")
650+
(PStr
651+
[
652+
Str.eval
653+
@@ Exp.constant (Const.string "react-hook-form");
654+
]);
655+
]
656+
~prim:[ "useWatch" ]
657+
(mknoloc @@ "useWatchOf" ^ capitalize record_name)
658+
(uncurried_core_type_arrow ~arity:1
659+
[
660+
Typ.arrow Nolabel
661+
(Typ.constr ~attrs:[ attr_named_arg ]
662+
(lid @@ "useWatchParamsOf" ^ capitalize record_name)
663+
[])
664+
(Typ.constr (lid "option")
665+
[
666+
Typ.constr
667+
(lid @@ "valuesOf" ^ capitalize record_name)
668+
[];
669+
]);
670+
]))
671+
in
672+
673+
let type_decls5 =
603674
lds
604675
|> List.filter_map
605676
(fun
@@ -799,8 +870,10 @@ let map_type_decl
799870
type_decls3;
800871
primitive_use_form;
801872
module_controller;
873+
type_decls4;
874+
primitive_use_watch;
802875
]
803-
@ type_decls4 @ primitive_use_field_array @ vd_field_array
876+
@ type_decls5 @ primitive_use_field_array @ vd_field_array
804877
| _ -> fail ptype_loc "This type is not handled by @ppx_react_hook_form"
805878
else []
806879

src/ppx/structure.ml

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,78 @@ let map_type_decl
598598
]))
599599
in
600600

601+
(* type useWatchParamsOfInputs = {
602+
name: variantOfInputs,
603+
control: controlOfInputs=?,
604+
defaultValue: valuesOfInputs=?,
605+
disabled: bool=?,
606+
exact: bool=?,
607+
} *)
601608
let type_decls4 =
609+
Str.type_ Recursive
610+
[
611+
Type.mk
612+
(mkloc ("useWatchParamsOf" ^ capitalize record_name) ptype_loc)
613+
~priv:Public
614+
~kind:
615+
(Ptype_record
616+
[
617+
Type.field ~mut:Immutable (mknoloc "name")
618+
(Typ.constr
619+
(lid @@ "variantOf" ^ capitalize record_name)
620+
[]);
621+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
622+
(mknoloc "control")
623+
(Typ.constr ~attrs:[ attr_named_arg ]
624+
(lid @@ "controlOf" ^ capitalize record_name)
625+
[]);
626+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
627+
(mknoloc "defaultValue")
628+
(Typ.constr
629+
(lid @@ "valuesOf" ^ capitalize record_name)
630+
[]);
631+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
632+
(mknoloc "disabled")
633+
(Typ.constr (lid "bool") []);
634+
Type.field ~attrs:[ attr_optional ] ~mut:Immutable
635+
(mknoloc "exact")
636+
(Typ.constr (lid "bool") []);
637+
]);
638+
]
639+
in
640+
641+
(* @module("react-hook-form")
642+
external useWatchOfInputs: useWatchParamsOfInputs => option<valuesOfInputs> = "useWatch" *)
643+
let primitive_use_watch =
644+
Str.primitive
645+
(Val.mk
646+
~attrs:
647+
[
648+
Attr.mk (mknoloc "module")
649+
(PStr
650+
[
651+
Str.eval
652+
@@ Exp.constant (Const.string "react-hook-form");
653+
]);
654+
]
655+
~prim:[ "useWatch" ]
656+
(mknoloc @@ "useWatchOf" ^ capitalize record_name)
657+
(uncurried_core_type_arrow ~arity:1
658+
[
659+
Typ.arrow Nolabel
660+
(Typ.constr ~attrs:[ attr_named_arg ]
661+
(lid @@ "useWatchParamsOf" ^ capitalize record_name)
662+
[])
663+
(Typ.constr (lid "option")
664+
[
665+
Typ.constr
666+
(lid @@ "valuesOf" ^ capitalize record_name)
667+
[];
668+
]);
669+
]))
670+
in
671+
672+
let type_decls5 =
602673
lds
603674
|> List.filter_map
604675
(fun
@@ -987,8 +1058,10 @@ let map_type_decl
9871058
type_decls3;
9881059
primitive_use_form;
9891060
module_controller;
1061+
type_decls4;
1062+
primitive_use_watch;
9901063
]
991-
@ type_decls4 @ primitive_use_field_array @ vb_field_array
1064+
@ type_decls5 @ primitive_use_field_array @ vb_field_array
9921065
| _ -> fail ptype_loc "This type is not handled by @ppx_react_hook_form"
9931066
else []
9941067

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useForm, SubmitHandler, useWatch } from "react-hook-form"
2+
3+
type Inputs = {
4+
example: string
5+
exampleRequired: string
6+
}
7+
8+
export default function UseWatch() {
9+
const {
10+
register,
11+
control,
12+
handleSubmit,
13+
formState: { errors },
14+
} = useForm<Inputs>()
15+
const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)
16+
17+
const value = useWatch({ name: "example", control, defaultValue: "test" })
18+
19+
console.log(value) // watch input value by passing the name of it
20+
21+
return (
22+
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
23+
<form onSubmit={handleSubmit(onSubmit)}>
24+
{/* register your input into the hook by invoking the "register" function */}
25+
<input defaultValue="test" {...register("example")} />
26+
27+
{/* include validation with required or other standard HTML validation rules */}
28+
<input {...register("exampleRequired", { required: true })} />
29+
{/* errors will return when field validation fails */}
30+
{errors.exampleRequired && <span>This field is required</span>}
31+
32+
<input type="submit" />
33+
</form>
34+
)
35+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
@rhf
2+
type inputs = {
3+
example?: string,
4+
exampleRequired: string,
5+
}
6+
7+
@react.component @genType
8+
let default = () => {
9+
let {register, control, handleSubmit, formState} = useFormOfInputs()
10+
let onSubmit = (data: inputs) => Js.log(data)
11+
12+
let example = useWatchOfInputs({name: Example, control, defaultValue: String("test")})
13+
14+
Js.log(example)
15+
16+
<form onSubmit={handleSubmit(onSubmit)}>
17+
<input {...register(Example)} defaultValue="test" />
18+
<input {...register(ExampleRequired, ~options={required: true})} />
19+
{formState.errors.exampleRequired->Belt.Option.isSome
20+
? <span> {"This field is required"->React.string} </span>
21+
: React.null}
22+
<input type_="submit" />
23+
</form>
24+
}

test/src/router/index.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import Controller from "../pages/controller/Controller"
1010
import ControllerRes from "../pages/controller_res/Controller.gen"
1111
import FieldArray from "../pages/field_array/FieldArray";
1212
import FieldArrayRes from "../pages/field_array_res/FieldArray.gen";
13-
13+
import UseWatch from "../pages/use_watch/UseWatch";
14+
import UseWatchRes from "../pages/use_watch_res/UseWatch.gen";
1415
const router = createBrowserRouter([
1516
{
1617
path: "/",
@@ -48,6 +49,14 @@ const router = createBrowserRouter([
4849
path: "/field_array_res",
4950
element: <FieldArrayRes />
5051
},
52+
{
53+
path: "/use_watch",
54+
element: <UseWatch />
55+
},
56+
{
57+
path: "/use_watch_res",
58+
element: <UseWatchRes />
59+
},
5160
])
5261

5362
export default router

0 commit comments

Comments
 (0)