Skip to content

Commit

Permalink
Add example 11
Browse files Browse the repository at this point in the history
  • Loading branch information
taschetto committed Mar 31, 2021
1 parent 671e923 commit d4d1eaf
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import Example07 from './examples/07'
import Example08 from './examples/08'
import Example09 from './examples/09'
import Example10 from './examples/10'
import Example11 from './examples/11'
import Example11 from './examples/11/index'
import Example12 from './examples/12/index'

const examples = [
{ key: 1, Component: Example01 },
Expand All @@ -36,6 +37,7 @@ const examples = [
{ key: 9, Component: Example09 },
{ key: 10, Component: Example10 },
{ key: 11, Component: Example11 },
{ key: 12, Component: Example12 },
]

const fallbackUi = () => <h1>Example not found</h1>
Expand Down
23 changes: 23 additions & 0 deletions src/examples/11/Form/Button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useFormContext } from 'react-hook-form'
import { Button as MuiButton } from '@material-ui/core'

export const Button = ({
children = 'Submit',
variant = 'outlined',
fullWidth = true,
...props
}) => {
const {
formState: { isSubmitting },
} = useFormContext()

return (
<MuiButton
{...props}
disabled={isSubmitting}
variant={variant}
fullWidth={fullWidth}>
{children}
</MuiButton>
)
}
17 changes: 17 additions & 0 deletions src/examples/11/Form/FormProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {
FormProvider as ReactHookFormProvider,
useFormContext,
} from 'react-hook-form'
import { DevTool } from '@hookform/devtools'

export const FormProvider = ({ children, ...other }) => (
<ReactHookFormProvider {...other}>
{children}
<DevTools />
</ReactHookFormProvider>
)

const DevTools = () => {
const { control } = useFormContext()
return <DevTool control={control} />
}
36 changes: 36 additions & 0 deletions src/examples/11/Form/Input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useFormContext, Controller } from 'react-hook-form'
import { TextField } from '@material-ui/core'
import { path } from 'ramda'

export const Input = ({ name, label, defaultValue = '' }) => {
const {
register,
formState: { isSubmitting },
errors,
control,
} = useFormContext()

const disabled = isSubmitting
const helperText = path([name, 'message'], errors)
const error = Boolean(helperText)

return (
<Controller
as={
<TextField
name={name}
label={label}
ref={register}
disabled={disabled}
helperText={helperText}
error={error}
variant='filled'
fullWidth
/>
}
name={name}
control={control}
defaultValue={defaultValue}
/>
)
}
5 changes: 5 additions & 0 deletions src/examples/11/Form/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { Button } from './Button'
export { Input } from './Input'
export { FormProvider } from './FormProvider'
export { useForm } from './useForm'
export { setAsyncError } from './setAsyncError'
7 changes: 7 additions & 0 deletions src/examples/11/Form/setAsyncError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { compose, forEach, path } from 'ramda'

export const setAsyncError = setErrorCallback =>
compose(
forEach(({ name, message }) => setErrorCallback(name, { message })),
path(['response', 'data', 'errors'])
)
32 changes: 32 additions & 0 deletions src/examples/11/Form/useForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useCallback } from 'react'
import { useState } from 'react'
import { useForm as useRHForm } from 'react-hook-form'

export const useForm = (...args) => {
const [formWideError, setFormWideError] = useState('')
const { handleSubmit: RHFhandleSubmit, ...formProps } = useRHForm(...args)

/**
* We need this custom submit handler because, typically, we will use a
* `mutateAsync` function from `react-query` to submit a form. These functions
* will throw any errors (422, 500, for example). Since the error is already
* handled by the mutation itself, we need to prevent this error from leaking.
*
* The original handler is exported as `RHFhandleSubmit`.
*
* @see {@link https://codesandbox.io/s/blissful-ride-wxxhl?file=/src/App.js}
* @see {@link https://codesandbox.io/s/30xos?file=/src/App.js}
*/
const handleSubmit = useCallback(
onSubmit => RHFhandleSubmit(data => onSubmit(data).catch(() => {})),
[RHFhandleSubmit]
)

return {
...formProps,
formWideError,
setFormWideError,
handleSubmit,
RHFhandleSubmit,
}
}
34 changes: 34 additions & 0 deletions src/examples/11/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { yupResolver } from '@hookform/resolvers/yup'
import { Grid } from '@material-ui/core'
import { useCustomMutation } from './useCustomMutation'
import { schema } from './schema'
import { FormProvider, useForm, Input, Button, setAsyncError } from './Form'

export default () => {
const formProps = useForm({ resolver: yupResolver(schema) })
const { handleSubmit, setError } = formProps
const { mutateAsync } = useCustomMutation({
onError: setAsyncError(setError),
})

return (
<FormProvider {...formProps}>
<form onSubmit={handleSubmit(mutateAsync)}>
<Grid container spacing={2}>
<Grid item xs={12}>
<h1>Organizing components</h1>
</Grid>
<Grid item xs={4}>
<Input name='firstName' defaultValue='John' label='First name' />
</Grid>
<Grid item xs={4}>
<Input name='lastName' defaultValue='Doe' label='Last name' />
</Grid>
<Grid item xs={4}>
<Button type='submit' />
</Grid>
</Grid>
</form>
</FormProvider>
)
}
6 changes: 6 additions & 0 deletions src/examples/11/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as yup from 'yup'

export const schema = yup.object().shape({
firstName: yup.string().required(),
lastName: yup.string().required(),
})
7 changes: 7 additions & 0 deletions src/examples/11/useCustomMutation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { instance } from 'api'
import { useMutation } from 'react-query'

export const useCustomMutation = (options = {}) =>
useMutation(async () => await instance.post('/unprocessable-entity'), {
...options,
})

0 comments on commit d4d1eaf

Please sign in to comment.