Skip to content

0.9.0

Compare
Choose a tag to compare
@wsmd wsmd released this 24 Mar 18:05
· 48 commits to master since this release

πŸš€ Features

Custom input validation errors

It's now possible to specify custom validation errors for invalid inputs. These errors can be retrieved from the form state for rendering purposes.

A validation error can be specified using the existing validate method. An input is considered invalid if this method returns false, non-empty strings, non-empty objects, non-empty arrays, etc.

<input
  {...password({
    name: 'password',
    validate: (value, values, event) => {
      const errors = {};
      if (!value) {
        errors.required = 'Password is required';
      }
      if (!STRONG_PASSWORD_REGEX.test(value)) {
        errors.weak = 'Password is not strong enough';
      }
      return errors; // empty objects are not considered errors!
    },
  })}
/>

When this input is invalid, you'll notice the returned value from the validate method available in the form state under errors.password.

{
  errors: {
    // the value of errors.password is determined via the validate method
    password: {
      weak: 'Password is not strong enough',
      required: 'Password is required',
    },
  }
}

Further reading:

✨ Improvements

The input's validate method gives you access to the change/blur event

It's now possible to access the change/blur event via the validate method. This can helpful if you want to access the underlying DOM node to perform certain checks.

<input
  required
  pattern={VALID_USERNAME_REGEX}
  minLength={4}
  text({
    name: 'username',
    validate: (value, values, e) => {
      if (e.target.validity.valueMissing) {
        return 'Value is required';
      } else if (e.target.validity.tooShort) {
        return 'Value is too short';
      } else if (e.target.patternMismatch) {
        return 'Value does not match the required';
      }
    },
  })
/>

Generated props are now memoizable (no more unnecessary re-renders)

In the past a change to an input resulted in re-rendering the entire form. That is not longer the case. The props generated by the input calls are now memoizable. This means that memoized input components will not re-render if their values remain the same.

const MemoizedInput = React.memo((props) => (
  <input {...props} />
));

const MyForm = () => {
  const [formState, { text, password }] = useFormState();
  return (
    <>
      {/* these inputs only re-render if their values actually changed */}
      <MemoizedInput {...text('username')} />
      <MemoizedInput {...password('password')} />
    </>
  )
}

πŸ“¦ Other Changes

  • Refactored tests (#42)
  • Fix typos in README (#46)

A special thanks to all the contributors that helped make this release possible! πŸ™‡β€β™‚οΈ