Skip to content

Commit 1561b46

Browse files
committed
feat(form): 组件添加校验时机参数
1 parent bdd57d5 commit 1561b46

File tree

5 files changed

+185
-15
lines changed

5 files changed

+185
-15
lines changed

src/components/Form/FormItem/index.tsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,14 @@ import { useId } from '../../../utils/hooks'
3333
*/
3434
const Item: React.FC<HuiFormItemProps> = (props) => {
3535
const context = useContext<FieldContext>(Context)
36-
const { registerWatch, getFieldValue, setFieldValue, removeFieldValue } =
37-
context
36+
const {
37+
registerWatch,
38+
getFieldValue,
39+
getFieldInfo,
40+
setFieldValue,
41+
removeFieldValue,
42+
updateShouldValidate,
43+
} = context
3844
const listContext = useContext<FormListContextProps>(FormListContext)
3945
const [renderType, setRenderType] = useState<keyof ItemType>('other')
4046
const [, update] = useState({})
@@ -118,7 +124,7 @@ const Item: React.FC<HuiFormItemProps> = (props) => {
118124
</View>
119125
)
120126

121-
const localValue = getFieldValue(path)
127+
const [localValue, shouldValidate] = getFieldInfo(path)
122128

123129
const onChange = useCallback(
124130
(event) => {
@@ -174,15 +180,20 @@ const Item: React.FC<HuiFormItemProps> = (props) => {
174180
name: path,
175181
}
176182
} catch (error) {
177-
throw new Error(error)
183+
throw new Error(error as string)
184+
} finally {
185+
updateShouldValidate(path, true)
178186
}
179187
},
180-
[getFieldValue, path, renderType, rule],
188+
[getFieldValue, path, renderType, rule, updateShouldValidate],
181189
)
182190

183191
useEffect(() => {
184-
validatorRules(localValue)
185-
}, [localValue])
192+
// 如果shouldValidate为false,则不进行验证
193+
if (shouldValidate) {
194+
validatorRules(localValue)
195+
}
196+
}, [localValue, shouldValidate])
186197

187198
// 组件卸载后移出字段
188199
useEffect(() => () => removeFieldValue(path), [path, removeFieldValue])

src/components/Form/FormStore/index.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import unset from 'lodash/unset'
55
import { toArray, getErrorTarget, toString } from '../util'
66
import {
77
FieldContext,
8+
FieldOptions,
89
FieldWatchCallback,
910
registerWatchType,
1011
} from '../constants'
@@ -31,6 +32,8 @@ class FormStore {
3132

3233
timer: number | undefined
3334

35+
shouldValidateMap: Record<string, boolean>
36+
3437
constructor() {
3538
this.store = {}
3639

@@ -53,6 +56,8 @@ class FormStore {
5356
this.pendingUnset = []
5457

5558
this.timer = undefined
59+
60+
this.shouldValidateMap = {}
5661
}
5762

5863
registerWatch(id: string, field: registerWatchType): () => void {
@@ -112,19 +117,37 @@ class FormStore {
112117

113118
getFieldsValue = (): any => this.store
114119

115-
setFieldValue<T>(name: string | string[], value: T): void {
120+
setFieldValue<T>(
121+
name: string | string[],
122+
value: T,
123+
options?: FieldOptions,
124+
): void {
116125
if (this.getFieldValue(name) !== value) {
117126
set(this.store, toArray(name), value)
127+
set(
128+
this.shouldValidateMap,
129+
toArray(name),
130+
options?.shouldValidate ?? true,
131+
)
118132
this.handleChange({ name, value })
119133
this.notifywatchList(name)
120134
}
121135
}
122136

123-
setFieldsValue(newStore: Store): void {
137+
setFieldsValue(newStore: Store, options?: FieldOptions): void {
124138
const newStoreTarget = {
125139
...this.store,
126140
...newStore,
127141
}
142+
for (const key in newStore) {
143+
if (Object.prototype.hasOwnProperty.call(newStore, key)) {
144+
set(
145+
this.shouldValidateMap,
146+
toArray(key),
147+
options?.shouldValidate ?? true,
148+
)
149+
}
150+
}
128151
this.updateStore(newStoreTarget)
129152
this.handleChange()
130153
this.notifywatchList()
@@ -236,6 +259,20 @@ class FormStore {
236259
} catch (error) {}
237260
}
238261

262+
private updateShouldValidate(
263+
name: string | string[],
264+
shouldValidate: boolean,
265+
): void {
266+
this.shouldValidateMap[toArray(name)?.join()] = shouldValidate
267+
}
268+
269+
private getFieldInfo(name: string | string[]): [any, boolean] {
270+
return [
271+
this.getFieldValue(name),
272+
this.shouldValidateMap[toArray(name)?.join()] ?? true,
273+
]
274+
}
275+
239276
getForm(): FieldContext {
240277
return {
241278
removeFieldValue: this.removeFieldValue.bind(this),
@@ -249,6 +286,8 @@ class FormStore {
249286
registerFieldWatch: this.registerFieldWatch.bind(this),
250287
submit: this.submit.bind(this),
251288
reset: this.reset.bind(this),
289+
updateShouldValidate: this.updateShouldValidate.bind(this),
290+
getFieldInfo: this.getFieldInfo.bind(this),
252291
}
253292
}
254293
}

src/components/Form/constants/index.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ export type NamePath = string | string[]
1414

1515
export type FieldWatchCallback = (values: any) => void
1616

17+
export type FieldOptions = {
18+
shouldValidate?: boolean
19+
}
20+
1721
export interface FieldContext {
1822
/** 删除单个表单数据 */
1923
removeFieldValue: (name: string | string[]) => void
@@ -22,9 +26,13 @@ export interface FieldContext {
2226
/** 获取所有表单数据 */
2327
getFieldsValue: () => any
2428
/** 设置所有表单数据 */
25-
setFieldsValue: (sotre: any) => any
29+
setFieldsValue: (sotre: any, options?: FieldOptions) => any
2630
/** 设置单个表单数据 */
27-
setFieldValue: (name: string | string[], value: any) => void
31+
setFieldValue: (
32+
name: string | string[],
33+
value: any,
34+
options?: FieldOptions,
35+
) => void
2836
/** 验证表单 */
2937
validatorFields: () => any
3038
/** 注册监听 */
@@ -37,6 +45,13 @@ export interface FieldContext {
3745
submit: () => Promise<{ type: 'success' | 'fail'; data: any }>
3846
/** 重制表单 */
3947
reset: () => Promise<void>
48+
/** 更新为初始化更新 */
49+
updateShouldValidate: (
50+
name: string | string[],
51+
shouldValidate: boolean,
52+
) => void
53+
/** 获取字段信息 */
54+
getFieldInfo: (name: string | string[]) => any
4055
}
4156

4257
const warningFunc = () => {}
@@ -53,6 +68,8 @@ const Context = React.createContext<FieldContext>({
5368
setCallbacks: warningFunc,
5469
submit: () => Promise.resolve().then(warningFunc as any),
5570
reset: () => Promise.resolve().then(warningFunc),
71+
updateShouldValidate: warningFunc,
72+
getFieldInfo: warningFunc,
5673
})
5774

5875
export interface FormItemContextProps {

src/pages/Form/Form.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import GroupSection from '@/demoComponents/GroupSection'
1111
import PageHeader from '@/demoComponents/PageHeader'
1212
import HuiRadio from '@/components/Radio'
1313

14+
import ShouldValidateForm from './components/shouldValidateForm'
15+
1416
import './Form.scss'
1517

1618
const BooleanRadioGroup: React.FC<{
@@ -95,10 +97,6 @@ const InputPage: React.FC = () => {
9597
setOpen1(false)
9698
}
9799

98-
useEffect(() => {
99-
form.setFieldsValue(localData)
100-
}, [])
101-
102100
const handleChange1 = useCallback((_cur, formData) => {
103101
setLocalData({ ...formData })
104102
}, [])
@@ -320,6 +318,8 @@ const InputPage: React.FC = () => {
320318
</HuiFormItem>
321319
</HuiForm>
322320
</GroupSection>
321+
322+
<ShouldValidateForm />
323323
</View>
324324
</View>
325325
)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import React, { useCallback, useEffect } from 'react'
2+
import HuiForm, { useForm } from '@/components/Form/index'
3+
import HuiButton from '@/components/Button/Button'
4+
import GroupSection from '@/demoComponents/GroupSection'
5+
import Taro from '@tarojs/taro'
6+
import HuiInput from '@/components/Input'
7+
import HuiTextArea from '@/components/TextArea'
8+
9+
const HuiFormItem = HuiForm.Item
10+
11+
const ShouldValidate: React.FC = () => {
12+
const [form] = useForm()
13+
14+
const handleReset = useCallback((f) => {
15+
Taro.showModal({
16+
title: '重置',
17+
content: `重置成功:'${JSON.stringify(f.getFieldsValue())}`,
18+
})
19+
}, [])
20+
21+
const handleFinish = useCallback((data) => {
22+
Taro.showModal({
23+
title: '提示',
24+
content: `提交成功:'${JSON.stringify(data)}`,
25+
})
26+
}, [])
27+
28+
useEffect(() => {
29+
form.setFieldsValue(
30+
{
31+
account: '1234567890',
32+
password: '',
33+
description: '',
34+
},
35+
{ shouldValidate: false },
36+
)
37+
}, [form])
38+
39+
return (
40+
<GroupSection title='form 校验时机'>
41+
<HuiForm
42+
form={form}
43+
onFinish={handleFinish}
44+
onReset={() => handleReset(form)}
45+
>
46+
<HuiFormItem
47+
rule={[
48+
{
49+
require: true,
50+
},
51+
(value) => value,
52+
]}
53+
label={(v) => `账号长度: ${v?.length ?? 0}`}
54+
name='account'
55+
>
56+
<HuiInput
57+
divider={false}
58+
onInput={(e) => form.setFieldValue('account', e.detail.value)}
59+
></HuiInput>
60+
</HuiFormItem>
61+
<HuiFormItem
62+
label='密码'
63+
name='password'
64+
rule={[
65+
{
66+
require: true,
67+
message: '密码必须填写',
68+
},
69+
]}
70+
tipsText='密码必须为6-10个字符之间'
71+
>
72+
<HuiInput
73+
divider={false}
74+
onInput={(e) => form.setFieldValue('password', e.detail.value)}
75+
type='safe-password'
76+
></HuiInput>
77+
</HuiFormItem>
78+
79+
<HuiFormItem
80+
rule={[{ require: true, message: '简介必须填写' }]}
81+
align='column'
82+
label='简介'
83+
name='description'
84+
>
85+
<HuiTextArea
86+
required={false}
87+
upperLimit={50}
88+
onInput={(e) => form.setFieldValue('description', e.detail.value)}
89+
></HuiTextArea>
90+
</HuiFormItem>
91+
92+
<HuiButton formType='submit' block style={{ margin: '12px 0' }}>
93+
提交表单
94+
</HuiButton>
95+
<HuiButton formType='reset' type='secondary' block>
96+
重置表单
97+
</HuiButton>
98+
</HuiForm>
99+
</GroupSection>
100+
)
101+
}
102+
103+
export default ShouldValidate

0 commit comments

Comments
 (0)