Skip to content
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

useForm #63

Open
revskill10 opened this issue Nov 2, 2018 · 7 comments
Open

useForm #63

revskill10 opened this issue Nov 2, 2018 · 7 comments
Labels
enhancement New feature or request

Comments

@revskill10
Copy link
Contributor

Any idea on useForm with (async) validation as a hook ?

@streamich
Copy link
Owner

What API do you imagine for that?

@revskill10
Copy link
Contributor Author

revskill10 commented Nov 2, 2018

@streamich I'm not sure about validation part, but for form, the api should be simple, based on standard html input types.

const { useCheckbox, useText, useImage, useRadio, useButton, useFile, 
useHidden, usePassword, useReset, useSubmit, useButton } = useForm()
const { value, setValue } = useCheckbox(defaultValue)
...

@streamich
Copy link
Owner

Maybe something like this:

const {useForm, useText, usePassword} = formHooks('my-form');

const Demo = () => {
  const state = useForm();
  const inputEmail = useText('email', 'Enter your e-mail');
  const inputPassword = usePassword('password', 'Password...');
  const onSubmit = useCallback(() => {
    // ...
  });

  return (
    <form onSubmit={onSubmit}>
      <input {...inputEmail} />
      <input {...inputPassword} />
      <button type="submit">Submit</button>
    </form>
  );
};

I don't know, it looks like there is a lot to think about.

@revskill10
Copy link
Contributor Author

revskill10 commented Nov 2, 2018

@streamich I'm testing this code:

import { useState } from 'react'
import Validator from 'fastest-validator'

export const useForm = (initialState, schema) => {
  const [values, setValues] = useState(initialState)
  const [errors, setErrors] = useState({})
  const v = new Validator();
  const check = v.compile(schema);
  
  const updateValues = (value, name) => {
    setValues({ ...values, [name]: value})
  }

  const onChange = (value, name) => {
    if (value.target) {
      const e = value
      updateValues(e.target.name, e.target.value)
    } else {
      updateValues(name, value)
    }
  }

  const onSubmit = (e) => {
    e.preventDefault()
    const errors = check(values)
    if (errors.length > 0) {
      setErrors(errors)
    } else {
      setErrors([])
    }
  }

  return {
    values,
    errors,
    onChange,
    onSubmit,
  }
} 

export default useForm

Usage like this

import { useForm } from 'lib/hooks/form'

const initialState = {
    firstName: "Truong",
    lastName: "Dung",
    age: 30,
  }

  const schema = {
    firstName: { type: "string" },
    lastName: { type: "string", optional: true },
    age: { type: "number", optional: true },
  }

const TestForm = () => {
  
  const {
    values,
    errors,
    onChange,
    onSubmit,
  } = useForm(initialState, schema)

  return (
    <div>
      <h1>New User</h1>
      <div>{JSON.stringify(errors)}</div>
      <form onSubmit={onSubmit} >
        <label>First name</label>
        <input type="text" name="firstName" onChange={onChange} value={values.firstName} />
        <label>Last name</label>
        <input type="text" name="lastName" onChange={onChange} value={values.lastName} />
        <label>Age</label>
        <input type="text" name="age" onChange={onChange} value={values.age} />
        <button type="submit">Submit</button>
      </form>
    </div>
  )
}

export default TestForm

There's an error that prevent field to change its value.

@cloudever
Copy link
Contributor

Formik will have form hooks, I think no need here

@streamich
Copy link
Owner

Here is a nice simple interface:

@wardoost wardoost added the enhancement New feature or request label Mar 31, 2019
@wardoost wardoost changed the title useForm ? useForm Mar 31, 2019
@brianle1301
Copy link

brianle1301 commented Jun 1, 2019

@streamich @revskill10 I prefer this API, which provides all the validation functionalities and uses validator under the hood.

const [
    { emai: { value, errorText, isValid } },
    handleFieldChange,
    handleFieldBlur,
    handleFieldFocus,
    validateFieldAfterSubmit,
  ] = useForm({
    email: {
      value: '',
      validationRules: [
        {
          method: isEmpty,
          validWhen: false,
          errorText: 'This field should not be left empty!',
        },
        {
          method: isEmail,
          errorText: 'This field should contain an email!',
        },
      ],
    },
  });

Then just plug all the returned functions into an input

<input onChange={handleFieldChange} onFocus={handleFieldFocus} onBlur={handleFieldBlur} value={value} />

I've implemented this hook naively (source code) and the demo of the hook can be found at the bottom of my portfolio: https://brian-le.surge.sh.

I could rewrite this hook for better performance and readability and open a PR if required :)

Edit: validateFieldAfterSubmit is used to validate each field one by one after submit, for example:

const handleSubmit = useCallback(
    async e => {
      e.preventDefault();

      if (!validateFieldAfterSubmit('email')) return;

      try {
        // async code here
      } catch (err) {
        setFormMsg('Oops, something went wrong');

        return;
      }

      setFormMsg('Success!');
    },
    [validateFieldAfterSubmit],
  );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants