0.1.0 • Published 4 years ago
simple-form-react v0.1.0
Simple Form React 📝
Custom React Hook for handling small & medium forms
Features
- Auto escape & trim inputs
- Auto check if any field (when
required: true
) or only required field (HTML elements withrequired
attribute; whenrequired: false
) is empty - Auto check if field, which name starts with
confirm
, matches its pair (e.g.password === confirmPassword
) - Accepts custom validators and error messages objects
Installation
yarn add simple-form-react
# or
npm i simple-form-react
Props
initialData
: { field: initial value }url
: string - endpoint for datamethod
: string -Post
by defaultrequired
- if
true
(default), all fields will be required - if
false
, only inputs with attributerequired
will be required - value of
disabled
indicator depends on that
- if
validators
: { (field) => validation logic }messages
: { field: error message }onChange
: functiononSubmit
: functionfetchOptions
: object - options forvery-simple-fetch
Returns
fields
: { field: value }change
: functionsubmit
: functionreset
: functiondisabled
: booleanloading
: booleanresponse
: any, including server errorserrors
: object - client (aka validation) errors
Usage
Form.js
// import { useState } from 'react'
import { Loader } from 'components'
import { Field } from './Field'
import { Button } from './Button'
import { Result } from './Result'
import { Error } from './Error'
import { defaultValidators, errorMessagesClient } from './validators'
import useSimpleForm, { simpleFetch } from 'simple-form-react'
simpleFetch.baseUrl = 'http://localhost:5000/api/auth'
export const Form = (props) => {
// const [data, setData] = useState(null)
const { children, inputs, validators, messages, submitLabel, ...rest } = props
const hookProps = {
...rest,
validators: { ...defaultValidators, ...validators },
messages: { ...errorMessagesClient, ...messages }
}
/*
hookProps.fetchOptions = {
handlers: {
onSuccess: (response) => {
setData(response.data)
}
}
}
*/
/*
hookProps.onSubmit = async (fields) => {
const response = await simpleFetch.post(rest.url, fields)
setData(response.data)
}
*/
const { fields, change, submit, reset, disabled, loading, response, errors } =
useSimpleForm(hookProps)
if (loading) return <Loader />
if (response?.data) return <Result result={response.data} />
// if (data) return <Result result={data} />
return (
<form onSubmit={submit} onReset={reset}>
{props.inputs.map((input, index) => (
<Field
key={index}
value={fields[input.name]}
onChange={change}
error={errors[input.name]}
{...input}
/>
))}
{children}
{response?.error && <Error status={response.info.status} />}
<div>
<Button label={submitLabel} variant='success' disabled={disabled} />
<Button label='Reset' type='reset' variant='warning' />
</div>
</form>
)
}
Field.js
const icons = ((i) => ({
name: `${i}-person`,
age: `${i}-person-fill`,
email: `${i}-envelope`,
password: `${i}-key`,
confirmPassword: `${i}-key-fill`
}))('bi bi')
export const Field = ({ label, name, error, ...rest }) => (
<div className='field'>
<label htmlFor={name} className='form-label'>
<i className={icons[name]}></i>
<span>{label}</span>
</label>
<input name={name} id={name} className='form-control' {...rest} />
<p className='text-danger'>{error}</p>
</div>
)
Button.js
const buttons = ((b) => ({
success: `${b}-success`,
warning: `${b}-warning`
}))('btn btn')
export const Button = ({ label, variant, ...rest }) => (
<button className={buttons[variant] || 'btn'} {...rest}>
{label}
</button>
)
Result.js
export const Result = ({ result }) => (
<>
<h4>Result</h4>
<div>
{Object.entries(result).map(([key, value], index) => (
<p key={index}>
{key}: {value}
</p>
))}
</div>
</>
)
Error.js
import { errorMessagesServer } from './validators'
export const Error = ({ status }) => (
<div className='text-danger'>
<p>{errorMessagesServer[status]}</p>
</div>
)
validators.js
const isEmail = (email) => /\S+@\S+\.\S+/.test(email)
export const defaultValidators = {
email: isEmail
}
export const errorMessagesClient = {
email: 'Wrong email!',
confirmPassword: 'Passwords must be the same!'
}
export const errorMessagesServer = {
404: 'User not found!',
403: 'Wrong credentials!',
409: 'Email already in use!',
500: 'Something went wrong. Try again later'
}
Login.js
import { Form } from 'components'
const inputs = [
{
label: 'Email',
name: 'email',
type: 'email'
},
{
label: 'Password',
name: 'password',
type: 'password'
}
]
const initialData = {
email: '',
password: ''
}
const formProps = {
initialData,
url: '/login',
inputs,
submitLabel: 'Login'
}
export const Login = () => (
<>
<h3>Login</h3>
<Form {...formProps} />
</>
)
Register.js
import { Form } from 'components'
const inputs = [
{
label: 'Name',
name: 'name',
type: 'text',
minlength: 2
},
{
label: 'Age',
name: 'age',
type: 'number',
min: 18,
max: 65,
step: 1
},
{
label: 'Email',
name: 'email',
type: 'email',
required: true
},
{
label: 'Password',
name: 'password',
type: 'password',
required: true
},
{
label: 'Confirm password',
name: 'confirmPassword',
type: 'password',
required: true
}
]
const validators = {
name: (value) => value.length > 1,
age: (value) => value > 17 && value < 66
}
const messages = {
name: 'Your name is too short!',
age: `You're too young or too old!`
}
const initialData = {
name: '',
age: '',
email: '',
password: '',
confirmPassword: ''
}
const formProps = {
initialData,
url: '/register',
inputs,
required: false,
validators,
messages,
submitLabel: 'Register'
}
export const Register = () => (
<>
<h3>Register</h3>
<Form {...formProps} />
</>
)