npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pickjunk/use-form

v1.1.5

Published

react form hook, so young, so simple

Downloads

7

Readme

use-form

NPM Version NPM Downloads

React Form Hook, so young, so simple.

Quick Start

$ npm i -S @pickjunk/use-form
import React from 'react';
import useForm from '@pickjunk/use-form';

export default function Greeting() {
  const form = useForm({
    who: {
      initValue: '',
      validators: [v => (!v ? 'who is required!' : '')],
    },
  });

  return (
    <div>
      <div style={{ marginBottom: 8 }}>hello {form.data('who') || '____'}</div>

      {form.field('who', function({
        value,
        setValue,
        validate,
        error,
        status,
      }) {
        return (
          <>
            <div>
              <input
                value={value}
                onChange={function(e) {
                  const v = e.currentTarget.value;
                  validate(v);
                  setValue(v);
                }}
              />
            </div>
            {status === 'fail' && <div style={{ color: 'red' }}>{error}</div>}
          </>
        );
      })}

      <button
        style={{ marginTop: 8 }}
        onClick={async function() {
          const valid = await form.validate();
          if (valid) {
            // submit
          }
        }}
      >
        submit
      </button>
    </div>
  );
}

Define Fields

useForm accept one argument to define fields.

interface Fields {
  [field: string]: {
    initValue: any;
    validators?: ((v: any) => string)[];
  };
}

Caution that you must not change the number and the sort of the fields in every rendering within the component. Because useForm will iterate the fields object and use react hook in the iteration. More details could be found in react hook official document.

Form Field

Once you have defined a form, feel free to render every field by form.field decorators. The decorator has two parameters, the first is field name, the second is a rendering callback.

In the rendering callback, things are intuitive. All status and methods about the field will be exported from the first parameter of the callback. They are value, setValue, validate, status and error.

Quick Start have demonstrated how things work. No much more to tell. If you want to know more details, typescript hints may help you when typing code.

Form Data

Get field data by form.data.

  • If you provide a field name, it will return the single field value: const who = form.data('who').

  • If you don't provide any field name, it will return all values of the fields, as a data object: const { who } = form.data().

Besides, remember the data object returned from form.data() is immutable, whick means it will always be a different reference as long as any of its properties has been changed.

Form Validate

Simply call await form.validate() when you want to validate all form fields before submitting, as Quick Start shows.

Internal Debounce

The validators of @pickjunk/use-form support debounce internally:

async function nameValid(name: string) {
  await new Promise(function (r) {
    setTimeout(r, 2000);
  });

  return '';
}
nameValid.debounce = 1500;

const form = useForm({
  name: {
    initValue: '',
    validators: [nameValid],
  },
});

Sub Form

The most powerful feature of @pickjunk/use-form is the elegant sub form. Look at the following example:

import React from 'react';
import useForm from '@pickjunk/use-form';

function SubForm({
  value,
  onChange,
}: {
  value: string;
  onChange: (v: string) => void;
}) {
  const form = useForm({
    value: {
      initValue: '',
      validators: [v => (!v ? 'who is required!' : '')],
    },
  });

  form.link('value', { value, onChange });

  return form.field('value', function({
    value,
    setValue,
    validate,
    error,
    status,
  }) {
    return (
      <>
        <div>
          <input
            value={value}
            onChange={function(e) {
              const v = e.currentTarget.value;
              validate(v);
              setValue(v);
            }}
          />
        </div>
        {status === 'fail' && <div style={{ color: 'red' }}>{error}</div>}
      </>
    );
  });
}

export default function Greeting() {
  const form = useForm({
    who: {
      initValue: '',
    },
  });

  return (
    <div>
      <div style={{ marginBottom: 8 }}>hello {form.data('who') || '____'}</div>

      {form.field('who', function({ value, setValue }) {
        return <SubForm value={value} onChange={setValue} />;
      })}

      <button
        style={{ marginTop: 8 }}
        onClick={async function() {
          const valid = await form.validate();
          if (valid) {
            // submit
          }
        }}
      >
        submit
      </button>
    </div>
  );
}

Obviously, it is equal to Quick Start. The different point is in the example in Sub Form, the input component is wrapped as a sub component. And in the sub component, a sub form is created.

Noticed that when we talk about sub form, actually it means two points:

  • In one hand, we want the sub form to take charge of its own validators. Besides, when calling form.validate() in the parent form, we expect the parent can notify all children to validate themselves.

  • In the other hand, we want to collect data from every children as a parent field value.

@pickjunk/use-form concrete these two points so wisely.

For the first point, an internal context will be created by every form.field decorator. Through these contexts, a tree of the form instances could be maintained. So it's easy to call form.validate in the parent form to notify all children validating themselves.

For the second point, form.link is provided to connect the data flow between parent and chilren easily. It has two types:

  • If you provide the field name, it links a single field of the sub form: form.link('field', { value, onChange }).

  • If you don't provide any field name, it links the whole data object of the sub form: form.link({ value, onChange }). Once again to remind, the data object is immutable.