Skip to content

feat(form): usewatch #2882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@
"classnames": "^2.5.1",
"lodash.isequal": "^4.5.0",
"lodash.kebabcase": "^4.1.1",
"react-transition-group": "^4.4.5"
"react-transition-group": "^4.4.5",
"rc-util": "^5.32.2"
},
"devDependencies": {
"@babel/core": "^7.23.9",
Expand Down
5 changes: 5 additions & 0 deletions src/packages/form/demo.taro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Demo4 from './demos/taro/demo4'
import Demo5 from './demos/taro/demo5'
import Demo6 from './demos/taro/demo6'
import Demo7 from './demos/taro/demo7'
import Demo8 from './demos/taro/demo8'

const FormDemo = () => {
const [translated] = useTranslate({
Expand All @@ -19,6 +20,7 @@ const FormDemo = () => {
relatedDisplay: '关联展示',
title4: 'Form.useForm 对表单数据域进行交互。',
title5: '表单类型',
title6: 'Form.useWatch 对表单数据监听',
validateTrigger: '校验触发时机',
},
'en-US': {
Expand All @@ -28,6 +30,7 @@ const FormDemo = () => {
relatedDisplay: 'Related Display',
title4: 'Interact with form data fields via Form.useForm',
title5: 'Form Type',
title6: 'Watch field data change with Form.useWatch',
validateTrigger: 'Validate Trigger',
},
})
Expand All @@ -50,6 +53,8 @@ const FormDemo = () => {
<Demo6 />
<h2>{translated.title5}</h2>
<Demo7 />
<h2>{translated.title6}</h2>
<Demo8 />
</div>
</>
)
Expand Down
5 changes: 5 additions & 0 deletions src/packages/form/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Demo4 from './demos/h5/demo4'
import Demo5 from './demos/h5/demo5'
import Demo6 from './demos/h5/demo6'
import Demo7 from './demos/h5/demo7'
import Demo8 from './demos/h5/demo8'

const FormDemo = () => {
const [translated] = useTranslate({
Expand All @@ -17,6 +18,7 @@ const FormDemo = () => {
relatedDisplay: '关联展示',
title4: 'Form.useForm 对表单数据域进行交互。',
title5: '表单类型',
title6: 'Form.useWatch 对表单数据监听',
validateTrigger: '校验触发时机',
},
'en-US': {
Expand All @@ -26,6 +28,7 @@ const FormDemo = () => {
relatedDisplay: 'Related Display',
title4: 'Interact with form data fields via Form.useForm',
title5: 'Form Type',
title6: 'Watch field data change with Form.useWatch',
validateTrigger: 'Validate Trigger',
},
})
Expand All @@ -47,6 +50,8 @@ const FormDemo = () => {
<Demo6 />
<h2>{translated.title5}</h2>
<Demo7 />
<h2>{translated.title6}</h2>
<Demo8 />
</div>
</>
)
Expand Down
100 changes: 100 additions & 0 deletions src/packages/form/demos/h5/demo8.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React from 'react'
import { Cell, Form, Input, Picker, Radio, Toast } from '@nutui/nutui-react'
import { ArrowRight } from '@nutui/icons-react'

const Demo8 = () => {
const pickerOptions = [
{ value: 4, text: 'BeiJing' },
{ value: 1, text: 'NanJing' },
{ value: 2, text: 'WuXi' },
{ value: 8, text: 'DaQing' },
{ value: 9, text: 'SuiHua' },
{ value: 10, text: 'WeiFang' },
{ value: 12, text: 'ShiJiaZhuang' },
]
const submitFailed = (error: any) => {
Toast.show({ content: JSON.stringify(error), icon: 'fail' })
}

const submitSucceed = (values: any) => {
Toast.show({ content: JSON.stringify(values), icon: 'success' })
}

const [form] = Form.useForm()
const usernameWatch = Form.useWatch('username', form)

const noteWatch = Form.useWatch((values) => {
return values.picker
}, form)

const genderWatch = Form.useWatch((values) => {
return values.gender
}, form)

return (
<>
<Form
form={form}
onFinish={(values) => submitSucceed(values)}
onFinishFailed={(values, errors) => submitFailed(errors)}
>
<Form.Item
label="字段A"
name="username"
initialValue="默认值"
rules={[{ required: true, message: '请输入字段A' }]}
>
<Input placeholder="请输入字段A" type="text" />
</Form.Item>
<Form.Item
label="Picker"
name="picker"
trigger="onConfirm"
getValueFromEvent={(...args) => args[1]}
onClick={(event, ref: any) => {
ref.open()
}}
>
<Picker options={[pickerOptions]}>
{(value: any) => {
return (
<Cell
style={{
padding: 0,
'--nutui-cell-divider-border-bottom': '0',
}}
className="nutui-cell--clickable"
title={
value.length
? pickerOptions.filter((po) => po.value === value[0])[0]
?.text
: 'Please select'
}
extra={<ArrowRight />}
align="center"
/>
)
}}
</Picker>
</Form.Item>
<Form.Item label="字段B" name="gender">
<Radio.Group>
<Radio value="male">male</Radio>
<Radio value="female">female</Radio>
</Radio.Group>
</Form.Item>
</Form>
<Cell>
<div>字段A:{usernameWatch}</div>
</Cell>
<Cell>
<div>Picker:{noteWatch}</div>
</Cell>
<Cell>
<div>字段B:{genderWatch}</div>
</Cell>
</>
)
}

export default Demo8
101 changes: 101 additions & 0 deletions src/packages/form/demos/taro/demo8.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react'
import Taro from '@tarojs/taro'
import { Cell, Form, Input, Picker, Radio } from '@nutui/nutui-react-taro'
import { ArrowRight } from '@nutui/icons-react-taro'

const Demo8 = () => {
const pickerOptions = [
{ value: 4, text: 'BeiJing' },
{ value: 1, text: 'NanJing' },
{ value: 2, text: 'WuXi' },
{ value: 8, text: 'DaQing' },
{ value: 9, text: 'SuiHua' },
{ value: 10, text: 'WeiFang' },
{ value: 12, text: 'ShiJiaZhuang' },
]
const submitFailed = (error: any) => {
Taro.showToast({ title: JSON.stringify(error), icon: 'error' })
}

const submitSucceed = (values: any) => {
Taro.showToast({ title: JSON.stringify(values), icon: 'success' })
}

const [form] = Form.useForm()
const usernameWatch = Form.useWatch('username', form)

const noteWatch = Form.useWatch((values) => {
return values.picker
}, form)

const genderWatch = Form.useWatch((values) => {
return values.gender
}, form)

return (
<>
<Form
form={form}
onFinish={(values) => submitSucceed(values)}
onFinishFailed={(values, errors) => submitFailed(errors)}
>
<Form.Item
label="字段A"
name="username"
initialValue="默认值"
rules={[{ required: true, message: '请输入字段A' }]}
>
<Input placeholder="请输入字段A" type="text" />
</Form.Item>
<Form.Item
label="Picker"
name="picker"
trigger="onConfirm"
getValueFromEvent={(...args) => args[1]}
onClick={(event, ref: any) => {
ref.open()
}}
>
<Picker options={[pickerOptions]}>
{(value: any) => {
return (
<Cell
style={{
padding: 0,
'--nutui-cell-divider-border-bottom': '0',
}}
className="nutui-cell--clickable"
title={
value.length
? pickerOptions.filter((po) => po.value === value[0])[0]
?.text
: 'Please select'
}
extra={<ArrowRight />}
align="center"
/>
)
}}
</Picker>
</Form.Item>
<Form.Item label="字段B" name="gender">
<Radio.Group>
<Radio value="male">male</Radio>
<Radio value="female">female</Radio>
</Radio.Group>
</Form.Item>
</Form>
<Cell>
<div>字段A:{usernameWatch}</div>
</Cell>
<Cell>
<div>Picker:{noteWatch}</div>
</Cell>
<Cell>
<div>字段B:{genderWatch}</div>
</Cell>
</>
)
}

export default Demo8
17 changes: 15 additions & 2 deletions src/packages/form/doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ import { Form } from '@nutui/nutui-react'

:::

### Form.useWatch 对表单数据监听

:::demo

<CodeBlock src='h5/demo8.tsx'></CodeBlock>

:::

## Form

### Props
Expand Down Expand Up @@ -120,8 +128,6 @@ import { Form } from '@nutui/nutui-react'

### FormInstance

Form.useForm()创建 Form 实例,用于管理所有数据状态。

| 属性 | 说明 | 类型 |
| --- | --- | --- |
| getFieldValue | 获取对应字段名的值 | `(name: NamePath) => any` |
Expand All @@ -131,6 +137,13 @@ Form.useForm()创建 Form 实例,用于管理所有数据状态。
| resetFields | 重置表单提示状态 | `() => void` |
| submit | 提交表单进行校验的方法 | `Promise` |

### Hook

| 方法名 | 说明 | 类型 |
| --- | --- | --- |
| Form.useForm | 创建 Form 实例,用于管理所有数据状态。 | `() => FormInstance` |
| Form.useWatch | 用于直接获取 form 中字段对应的值。 | `(name: NamePath \| (values: T) => any,options: FormInstance \| WatchOptions<FormInstance>) => any` |

## 主题定制

### 样式变量
Expand Down
3 changes: 3 additions & 0 deletions src/packages/form/index.taro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Form, FormProps } from './form.taro'
import { FormItem } from '../formitem/formitem.taro'
import { FormInstance } from './types'
import { useForm } from '@/packages/form/useform.taro'
import useWatch from './useWatch.taro'

export type {
FormItemRuleWithoutValidator,
Expand All @@ -17,11 +18,13 @@ type CompoundedComponent = React.ForwardRefExoticComponent<
> & {
Item: typeof FormItem
useForm: typeof useForm
useWatch: typeof useWatch
}

const InnerForm = Form as CompoundedComponent

InnerForm.Item = FormItem
InnerForm.useForm = useForm
InnerForm.useWatch = useWatch

export default InnerForm
3 changes: 3 additions & 0 deletions src/packages/form/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Form, FormProps } from './form'
import { FormItem } from '../formitem/formitem'
import { FormInstance } from './types'
import { useForm } from '@/packages/form/useform'
import useWatch from './useWatch'

export type {
FormItemRuleWithoutValidator,
Expand All @@ -17,11 +18,13 @@ type CompoundedComponent = React.ForwardRefExoticComponent<
> & {
Item: typeof FormItem
useForm: typeof useForm
useWatch: typeof useWatch
}

const InnerForm = Form as CompoundedComponent

InnerForm.Item = FormItem
InnerForm.useForm = useForm
InnerForm.useWatch = useWatch

export default InnerForm
10 changes: 10 additions & 0 deletions src/packages/form/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface FormItemRuleWithoutValidator {

type StoreValue = any
export type NamePath = string | number
export type InternalNamePath = (string | number)[]

export interface Callbacks<Values = any> {
onValuesChange?: (values: Values) => void
Expand All @@ -30,6 +31,15 @@ export interface FormInstance<Values = any> {
validateFields: (nameList?: NamePath[]) => Promise<any[]>
}

export type InternalFormInstance = FormInstance & { _init: boolean }

export type WatchCallBack = (
allValues: Store,
namePathList: InternalNamePath[]
) => void
export interface WatchOptions<Form extends FormInstance = FormInstance> {
form?: Form
}
export interface FormFieldEntity {
onStoreChange: (type?: string) => void
getNamePath: () => NamePath
Expand Down
Loading
Loading