0.4.4 • Published 7 months ago

jotai-decode-form v0.4.4

Weekly downloads
-
License
MIT
Repository
-
Last release
7 months ago

jotai-decode-form

[Japanese]

jotai-decode-form is a library designed for defining forms using Jotai. It aims to strictly separate the data structures of the application's internal and external environments.

Installation

$ npm i jotai-decode-form jotai

Motivation and Basic Usage

The primary goal of this library is to convert data types at the boundary of the program's external interface, adhering to specific specifications. Specifically, when implementing a form, we want to:

  1. Manage the data structures of the internal and external separately.
  2. Convert data mutually at the boundary (form) between the internal and external.

For instance, consider defining a field like width using standard Jotai to allow numeric input:

import { useAtom, atom } from 'jotai';

const widthAtom = atom();

const Field: React.FC = () => {
  const [value, onChange] = useAtom(widthAtom);

  return (
    <>
      <label htmlFor="width">width</label>
      <input
        id="width"
        value={value}
        onChange={e => onChange(e.target.value)}
      />
    </>
  );
};

In this scenario, we'd like to treat width internally as a number. However, with the current implementation, it's treated as a string. This issue is not unique to our library but is also prevalent in other form libraries.

Ideally, we'd want to handle string in the external world (field) and number internally. To achieve this, we can redefine the above atom using atomWithSchema provided by jotai-decode-form:

import { atomWithSchema } from 'jotai-decode-form';
import { useAtom } from 'jotai';
import { z } from 'zod';

type Width = number;

const widthAtom = atomWithSchema<Width>({
  schema: {
    fromView: z.coerce.number().safeParse,
    toView: String,
  },
});

Here, fromView specifies a function to convert from string to the internal data structure, which also serves as validation. In this example, we're using a function that forcibly converts to a number. Conversely, toView specifies a function to convert from the internal data structure to a string.

Using this new atom definition, you can access it using useAtom just like a regular atom:

const Field: React.FC = () => {
  const [field, onChange] = useAtom(widthAtom);

  return (
    <>
      <label htmlFor="width">width</label>
      <input
        id="width"
        value={field.exValue}
        onChange={e => onChange(e.target.value)}
      />
    </>
  );
};

Furthermore, when referencing the internal value, you'll get the expected number type:

const field = useAtomValue(widthAtom);
console.log(field.value); // 100
console.log(typeof field.value); // number

Additional Examples

For detailed implementations and more use cases, see examples.

Type Safety with Initial Values

With atomWithSchema, you can specify an initial value:

const widthAtom = atomWithSchema<Width>({
  initValue: 100,
});

Whether you've specified an initial value determines if the internal value (value) type is nullable. If there's an initial value, it's of type T. Without an initial value, it's T | null. This ensures type safety as handling becomes mandatory when there's no initial value.

Contributing

Welcome

LICENSE

MIT

0.4.4

7 months ago

0.4.3

7 months ago

0.4.1

9 months ago

0.3.2

9 months ago

0.4.0

9 months ago

0.3.1

9 months ago

0.4.2

8 months ago

0.3.0

9 months ago

0.2.0

9 months ago

0.1.2

9 months ago

0.1.1

9 months ago

0.1.0

9 months ago

0.0.2

9 months ago

0.0.1

9 months ago