Skip to content
This repository has been archived by the owner on Dec 27, 2022. It is now read-only.

Commit

Permalink
feat(hook): add useOnFieldChange
Browse files Browse the repository at this point in the history
  • Loading branch information
philibea committed Dec 21, 2022
1 parent 06b4de2 commit 41e7592
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 1 deletion.
111 changes: 111 additions & 0 deletions src/hooks/__tests__/useOnFieldChange.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { ThemeProvider } from '@emotion/react'
import { theme as lightTheme } from '@scaleway/ui'
import { renderHook } from '@testing-library/react'
import type { ReactElement } from 'react'
import { CheckboxField, Form, TextBoxField } from '../../components'
import { mockErrors } from '../../mocks'
import { useOnFieldChange } from '../useOnFieldChange'

type FormValues = {
textBoxName: string
check: boolean
}

type Wrapers = {
children: ReactElement
initialValues: FormValues
}

const initial = {
textBoxName: 'test',
check: true,
}

const updated = {
textBoxName: 'updated',
check: false,
}

const Wrapper = ({ children, initialValues }: Wrapers) => (
<ThemeProvider theme={lightTheme}>
<Form<FormValues>
initialValues={initialValues}
errors={mockErrors}
onRawSubmit={() => {}}
>
{children}
<CheckboxField name="check" />
<TextBoxField name="textBoxName" type="text" />
</Form>
</ThemeProvider>
)

describe('useOnFieldChange', () => {
test('should render correctly', () => {
const callback = jest.fn((value, values) => {
expect(value).toBe(updated.textBoxName)
expect(values).toBe(updated)
})

let initialValues = initial

const { result, rerender } = renderHook(
() =>
useOnFieldChange<FormValues['textBoxName'], FormValues>(
'textBoxName',
true,
callback,
),
{
wrapper: ({ children }) => (
<Wrapper initialValues={initialValues}>{children}</Wrapper>
),
},
)

expect(result.current).toBeUndefined()

expect(callback).toHaveBeenCalledTimes(0)

initialValues = updated

rerender()

expect(callback).toHaveBeenCalledTimes(1)
})

test('should render when condition change ', () => {
const callback = jest.fn()

let initialValues = initial

const { result, rerender } = renderHook(
({ condition }) => {
useOnFieldChange<FormValues['textBoxName'], FormValues>(
'textBoxName',
condition,
callback,
)
},
{
wrapper: ({ children }) => (
<Wrapper initialValues={initialValues}>{children}</Wrapper>
),

initialProps: {
condition: false,
},
},
)

expect(result.current).toBeUndefined()

expect(callback).toHaveBeenCalledTimes(0)

initialValues = updated

rerender({ condition: true })

expect(callback).toHaveBeenCalledTimes(1)
})
})
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { useValidation } from './useValidation'
export { useFormField } from './useFormField'
export { useOnFieldChange } from './useOnFieldChange'
29 changes: 29 additions & 0 deletions src/hooks/useOnFieldChange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useEffect, useRef } from 'react'
import { useField, useFormState } from 'react-final-form'

type CallbackFn<FieldValue, AllValues> = (
value: FieldValue,
values: AllValues,
) => unknown

export const useOnFieldChange = <FieldValue = unknown, AllValues = unknown>(
name: string,
condition: boolean,
callback: CallbackFn<FieldValue, AllValues>,
): void => {
const { values } = useFormState<AllValues>()
const {
input: { value },
} = useField<FieldValue>(name, {
allowNull: true,
subscription: { value: true },
})
const previousValues = useRef(value)

useEffect(() => {
if (previousValues.current !== value && condition) {
previousValues.current = value
callback(value, values)
}
}, [value, values, callback, condition])
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export {
TimeField,
ToggleField,
} from './components'
export { useValidation } from './hooks'
export { useValidation, useOnFieldChange } from './hooks'
export type { BaseFieldProps, FormErrors } from './types'
export { pickValidators } from './helpers'
export { useErrors, ErrorProvider } from './providers/ErrorContext'

0 comments on commit 41e7592

Please sign in to comment.