React Native-用 Formik 和 Yup 做表單驗證

很常見的功能。

懶人包

Formik 的部分

  1. 設定欄位的初始值
  2. 建立表單元件
  3. 把表單元件跟 formik 做資料雙向綁定
  4. 設定 submit 的 handler

Yup 的部分

其實就是建立一個 object,像這樣:

1
2
3
4
5
const formSchema = Yup.object({
'欄位1': 規則1,
'欄位2': 規則2,
'欄位3': 規則3,
})

規則的邏輯跟 propTypes 有點像,總之寫好後再跟 Formik 串起來就好了。

示範 Formik

簡單來說會建立一個 Formik 的元件,只要把東西寫在 Formik 在這個元件裡,就可以利用它提供的 props 來做到下面這些事情:

  • 設定欄位初始值
  • 管理欄位的 state
  • 用 Formik 的 action,例如 Reset 欄位的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { View, TextInput, Text, Button } from "react-native";
import { globalStyles } from "../style/globalStyle";
import { Formik } from "formik";

interface Props {
addReview: any
}

const ReviewForm: React.FC<Props> = ({ addReview }) => {
return (
<View style={globalStyles.container}>
<Formik
initialValues={{
title: '',
body: '',
rating: '',
}}

onSubmit={(values, action) => {
// 這邊可以拿到欄位的值
addReview(values);
// Formik 提供的 API
action.resetForm();
}}
>
{/* 這邊是 render function,可以拿到 Formik 提供的 props, */}
{(props) => (
<View>
<TextInput
style={globalStyles.input}
placeholder="Review titile"
onChangeText={props.handleChange('title')}
value={props.values.title}
/>
<TextInput
style={globalStyles.input}
multiline
placeholder="Review content"
onChangeText={props.handleChange('body')}
value={props.values.body}
/>
<TextInput
style={globalStyles.input}
keyboardType="numeric"
placeholder="Rating (1, 5)"
onChangeText={props.handleChange('rating')}
value={props.values.rating}
/>
<Button title="Submit" onPress={props.handleSubmit} />
</View>
)}
</Formik>
</View>
)
}
export default ReviewForm;

示範把 Yup 跟 Formik 串起來

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { View, TextInput, Text } from "react-native";
import { Button } from "../share/Button";
import { globalStyles } from "../style/globalStyle";
import { Formik } from "formik";
import * as Yup from "yup";

interface Props {
addReview: any
}

const reviewSchema = Yup.object({
title: Yup.string()
.required()
.min(4, 'Too short! It\'s must be greater than 4 charactor'),
body: Yup.string()
.required()
.min(8, 'Too short! It\'s must be greater than 8 charactor'),
rating: Yup.string()
.required()
.test('is num between 1 - 5', 'Rating must be a number 1 - 5', (val: any) => {
return parseInt(val, 10) > 0 && parseInt(val, 10) < 6
})
})


const ReviewForm: React.FC<Props> = ({ addReview }) => {
return (
<View style={globalStyles.container}>
<Formik
initialValues={{
title: '',
body: '',
rating: '',
}}
// 把規則傳入 props
validationSchema={reviewSchema}
onSubmit={(values, action) => {
addReview(values);
action.resetForm();
}}
>
{(props) => (
<View>
<TextInput
style={globalStyles.input}
placeholder="Review titile"
onChangeText={props.handleChange('title')}
onBlur={props.handleBlur('title')}
value={props.values.title}
/>
{/* Error Message */}
<Text style={globalStyles.errorText}>{props.touched.title && props.errors.title}</Text>
<TextInput
style={globalStyles.input}
multiline
placeholder="Review content"
onChangeText={props.handleChange('body')}
onBlur={props.handleBlur('body')}
value={props.values.body}
/>
<Text style={globalStyles.errorText}>{props.touched.body && props.errors.body}</Text>
<TextInput
style={globalStyles.input}
keyboardType="numeric"
placeholder="Rating (1, 5)"
onChangeText={props.handleChange('rating')}
onBlur={props.handleBlur('rating')}
value={props.values.rating}
/>
<Text style={globalStyles.errorText}>{props.touched.rating && props.errors.rating}</Text>
<Button title="Submit" onPress={props.handleSubmit} />
</View>
)}
</Formik>
</View>
)
}
export default ReviewForm;

附註:props.touched.title 是為了做出「碰過以後」才顯示 error message,不然全部的欄位會一次 pop 出來。

最後附上一下完成效果:

result

React Native-關於 Goole places autocomplete 的樣式 React Native 關於渲染列表的幾種方式
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×