Skip to content

Commit

Permalink
feat(@uform/react): remove raf and fix unittest (#422)
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnIsOnTheRoad authored and janryWang committed Nov 24, 2019
1 parent 908882a commit 670fadb
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 23 deletions.
91 changes: 90 additions & 1 deletion packages/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ npm install --save @uform/react
- [`Async Linkage`](#Async-Linkage)
- [`Linkage Validation`](#Linkage-Validation)
- [`Complex Linkage`](#Complex-Linkage)
- [`Reuse Effects`](#Reuse-Effects)
- [`Combo`](#Combo)
- [`Provide and FormSpy`](#Provide-and-FormSpy)
- [`Deconstruction`](#Deconstruction)
Expand Down Expand Up @@ -1022,6 +1023,94 @@ const App = () => {
ReactDOM.render(<App />, document.getElementById('root'))
```

#### Reuse Effects

Make your own reusable effects.

```jsx
import React from 'react'
import ReactDOM from 'react-dom'
import { Form, Field, createFormActions, FormEffectHooks } from '@uform/react'


const InputField = props => (
<Field {...props}>
{({ state, mutators }) => {
const loading = state.props.loading
return <React.Fragment>
{ props.label && <label>{props.label}</label> }
{ loading ? ' loading... ' : <input
disabled={!state.editable}
value={state.value || ''}
onChange={mutators.change}
onBlur={mutators.blur}
onFocus={mutators.focus}
/> }
<span style={{ color: 'red' }}>{state.errors}</span>
<span style={{ color: 'orange' }}>{state.warnings}</span>
</React.Fragment>
}}
</Field>
)
const CheckedField = props => (
<Field {...props}>
{({ state, mutators }) => {
const loading = state.props.loading
return <React.Fragment>
{ props.label && <label>{props.label}</label> }
{ loading ? ' loading... ' : <input type="checkbox" onChange={() => {
mutators.change(!state.value)
}} checked={!!state.value} /> }
<span style={{ color: 'red' }}>{state.errors}</span>
<span style={{ color: 'orange' }}>{state.warnings}</span>
</React.Fragment>
}}
</Field>
)

const { onFormMount$, onFieldValueChange$ } = FormEffectHooks
const getEffects = ()=>{
const actions = createFormActions()
onFormMount$().subscribe(() => {
actions.setFieldState('a~', state => state.visible = false)
})

onFieldValueChange$('trigger').subscribe((triggerState) => {
actions.setFieldState('a~', state => {
state.visible = triggerState.value
})
})

onFieldValueChange$('a').subscribe((fieldState) => {
actions.setFieldState('a-copy', state => {
state.value = fieldState.value
})
})
}

const actions = createFormActions()
const App = () => {
return (
<Form
actions={actions}
effects={() => {
getEffects()
}}
>
<CheckedField name="trigger" label="show/hide" />
<div>
<InputField label="a" name="a" />
</div>
<div>
<InputField label="a-copy" name="a-copy" />
</div>
</Form>
)
}

ReactDOM.render(<App />, document.getElementById('root'))
```

#### Combo

Example:Combo value of username and age. Check [FormSpy](#FormSpy) for more inforation.
Expand Down Expand Up @@ -1610,7 +1699,7 @@ const App = () => {
<Field name="user" initialValue={{}}>
{({ state, mutator }) => {
return (
<VirtualField name="layout">
<VirtualField name="user.layout">
{({ state: layoutState }) => {
return (
<Layout
Expand Down
93 changes: 92 additions & 1 deletion packages/react/README.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ npm install --save @uform/react
- [`异步联动`](#异步联动)
- [`联动校验`](#联动校验)
- [`复杂联动`](#复杂联动)
- [`复用Effects`](#复用Effects)
- [`combo字段`](#combo字段)
- [`跨文件消费表单数据`](#跨文件消费表单数据)
- [`简单解构`](#简单解构)
Expand Down Expand Up @@ -1027,6 +1028,96 @@ const App = () => {
ReactDOM.render(<App />, document.getElementById('root'))
```

#### 复用Effects

自定义可复用的effects


```jsx
import React from 'react'
import ReactDOM from 'react-dom'
import { Form, Field, createFormActions, FormEffectHooks } from '@uform/react'


const InputField = props => (
<Field {...props}>
{({ state, mutators }) => {
const loading = state.props.loading
return <React.Fragment>
{ props.label && <label>{props.label}</label> }
{ loading ? ' loading... ' : <input
disabled={!state.editable}
value={state.value || ''}
onChange={mutators.change}
onBlur={mutators.blur}
onFocus={mutators.focus}
/> }
<span style={{ color: 'red' }}>{state.errors}</span>
<span style={{ color: 'orange' }}>{state.warnings}</span>
</React.Fragment>
}}
</Field>
)
const CheckedField = props => (
<Field {...props}>
{({ state, mutators }) => {
const loading = state.props.loading
return <React.Fragment>
{ props.label && <label>{props.label}</label> }
{ loading ? ' loading... ' : <input type="checkbox" onChange={() => {
mutators.change(!state.value)
}} checked={!!state.value} /> }
<span style={{ color: 'red' }}>{state.errors}</span>
<span style={{ color: 'orange' }}>{state.warnings}</span>
</React.Fragment>
}}
</Field>
)

const { onFormMount$, onFieldValueChange$ } = FormEffectHooks
const getEffects = ()=>{
const actions = createFormActions()
onFormMount$().subscribe(() => {
actions.setFieldState('a~', state => state.visible = false)
})

onFieldValueChange$('trigger').subscribe((triggerState) => {
actions.setFieldState('a~', state => {
state.visible = triggerState.value
})
})

onFieldValueChange$('a').subscribe((fieldState) => {
actions.setFieldState('a-copy', state => {
state.value = fieldState.value
})
})
}

const actions = createFormActions()
const App = () => {
return (
<Form
actions={actions}
effects={() => {
getEffects()
}}
>
<CheckedField name="trigger" label="show/hide" />
<div>
<InputField label="a" name="a" />
</div>
<div>
<InputField label="a-copy" name="a-copy" />
</div>
</Form>
)
}

ReactDOM.render(<App />, document.getElementById('root'))
```


#### combo 字段

示例:combo username 和 age 字段, 更多用法,请点击[FormSpy](#FormSpy)查看
Expand Down Expand Up @@ -1644,7 +1735,7 @@ const App = () => {
<Field name="user" initialValue={{}}>
{({ state, mutator }) => {
return (
<VirtualField name="layout">
<VirtualField name="user.layout">
{({ state: layoutState }) => {
return (
<Layout
Expand Down
32 changes: 19 additions & 13 deletions packages/react/src/__tests__/useField.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,13 @@ describe('useField hook',()=>{
return <FormContext.Provider value={form}>{children}</FormContext.Provider>
}

const { result, waitForNextUpdate } = renderHook(() => useField({ name: 'username' }), { wrapper: formWrapper })
const { result } = renderHook(() => useField({ name: 'username' }), { wrapper: formWrapper })
expect(result.current.state.value).toEqual(undefined)
act(() => {
globalForm.setFormState(state => state.values.username = 'abcd')
})

// forceUpdate will trigger in raf, use waitForNextUpdate
expect(result.current.state.value).toEqual(undefined)
await waitForNextUpdate()
expect(result.current.state.value).toEqual('abcd')
expect(result.current.state.value).toEqual('abcd')
})

test('mounted change', async ()=>{
Expand Down Expand Up @@ -95,7 +92,7 @@ describe('useField hook',()=>{
editable: true,
rules: [],
}
const { result, waitForNextUpdate, rerender } = renderHook(() => useField(initialProps), { wrapper: formWrapper })
const { result, rerender } = renderHook(() => useField(initialProps), { wrapper: formWrapper })
expect(result.current.props).toEqual({ disabled: true })
expect(result.current.state.required).toEqual(false)
expect(result.current.state.editable).toEqual(true)
Expand All @@ -112,7 +109,6 @@ describe('useField hook',()=>{
expect(result.current.state.rules).toEqual([])

rerender()
await waitForNextUpdate()

expect(result.current.props).toEqual(initialProps.props)
expect(result.current.state.required).toEqual(initialProps.required)
Expand Down Expand Up @@ -152,19 +148,26 @@ describe('useField hook',()=>{
}

const fieldProps = { name: 'username', required: true }
const { result: result1, waitForNextUpdate: waitForNextUpdate1 } = renderHook(() => useField(fieldProps), { wrapper: formWrapper })
const { result: result1, rerender } = renderHook(() => useField(fieldProps), { wrapper: formWrapper })
expect(result1.current.state.errors).toEqual('')
expect(result1.current.state.value).toEqual(undefined)
result1.current.mutators.change('')
await waitForNextUpdate1()
rerender()
act(() => {
result1.current.mutators.change('')
})

// await waitForNextUpdate1()
expect(result1.current.state.value).toEqual('')
expect(result1.current.state.errors).toEqual('')

const { result: result2, waitForNextUpdate: waitForNextUpdate2 } = renderHook(() => useField({ ...fieldProps, triggerType: 'onChange' }), { wrapper: formWrapper })
expect(result2.current.state.errors).toEqual('')
expect(result2.current.state.value).toEqual(undefined)

result2.current.mutators.change('')
act(() => {
result2.current.mutators.change('')
})

await waitForNextUpdate2()
expect(result2.current.state.value).toEqual('')
expect(result2.current.state.errors).toEqual('This field is required')
Expand All @@ -179,16 +182,19 @@ describe('useField hook',()=>{
const fieldProps = { name: 'username', required: true }
const { result: result1, rerender } = renderHook(() => useField(fieldProps), { wrapper: formWrapper })
expect(result1.current.state.errors).toEqual('')
result1.current.mutators.blur()
rerender()
act(() => {
result1.current.mutators.blur()
})

expect(result1.current.state.errors).toEqual('')

const { result: result2, waitForNextUpdate: waitForNextUpdate2 } = renderHook(() => useField({ ...fieldProps, triggerType: 'onBlur' }), { wrapper: formWrapper })
expect(result2.current.state.errors).toEqual('')

act(() => {
result2.current.mutators.blur()
})
})
await waitForNextUpdate2()
expect(result2.current.state.errors).toEqual('This field is required')
})
Expand Down
10 changes: 2 additions & 8 deletions packages/react/src/__tests__/useVirtualField.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,12 @@ describe('useVirtualField hook',()=>{
return <FormContext.Provider value={form}>{children}</FormContext.Provider>
}

const { result, rerender } = renderHook(() => useVirtualField({ name: 'username' }), { wrapper: formWrapper })
const { result } = renderHook(() => useVirtualField({ name: 'username' }), { wrapper: formWrapper })
expect(result.current.state.visible).toEqual(true)
act(() => {
globalForm.setFieldState('username', state => state.visible = false)
})

// forceUpdate will trigger in raf, use waitForNextUpdate
expect(result.current.state.visible).toEqual(true)
rerender()
expect(result.current.state.visible).toEqual(false)
})

Expand Down Expand Up @@ -91,15 +88,12 @@ describe('useVirtualField hook',()=>{
name: 'username',
props: { disabled: true },
}
const { result, waitForNextUpdate, rerender } = renderHook(() => useVirtualField(initialProps), { wrapper: formWrapper })
const { result, rerender } = renderHook(() => useVirtualField(initialProps), { wrapper: formWrapper })
expect(result.current.props).toEqual({ disabled: true })
initialProps.props = { disabled: false }

expect(result.current.props).toEqual({ disabled: true })

rerender()
await waitForNextUpdate()

expect(result.current.props).toEqual(initialProps.props)
})
})

0 comments on commit 670fadb

Please sign in to comment.