Core

Lynx.ts Core
TypeScript-first, lightning fast Forms for React.js and React Native. The @lynxts/core package contains the main functionalities which can be used in any kind of React.js environment.
Requirements
React.js: >=16.8.0
Install
Using Yarn:
yarn add @lynxts/coreUsing NPM:
npm i @lynxts/coreUsage
Lynx.ts aims to make using forms as simple as possible, so you'll only need a few things to get started: The FormProvider, its validation schema, and some fields. We provide a few helpers to make things even easier and safer.
import { FormProvider, fieldOf } from "@lynxts/core";
import { ReactElement, memo, useCallback } from "react";
import { ObjectSchema, object, string } from "yup";
interface Login {
email: string;
password: string;
}
const schema: ObjectSchema<Login> = object({
email: string().email().required(),
password: string().required(),
});
const Field = fieldOf<Login>();
const SignIn = memo((): ReactElement => {
const handleSubmit = useCallback((values: Login): void => {
const { email, password } = values;
// Use the validated value to sign in!
}, []);
return (
<FormProvider onSubmit={handleSubmit} validation={schema}>
{({ submit }) => (
<>
<Field name="email" fallback="">
{({ handleChange, setTouched, value, required, error }) => (
<label>
{`Email:${required ? "*" : ""}`}
<input
type="email"
onChange={handleChange(e => e.target.value)}
onBlur={setTouched}
value={value}
/>
{error && <small>{error}</small>}
</label>
)}
</Field>
<Field name="password" fallback="">
{({ handleChange, setTouched, value, required, error }) => (
<label>
{`Password:${required ? "*" : ""}`}
<input
type="password"
onChange={handleChange(e => e.target.value)}
onBlur={setTouched}
value={value}
/>
{error && <small>{error}</small>}
</label>
)}
</Field>
<button type="button" onClick={submit}>
{"SignIn"}
</button>
</>
)}
</FormProvider>
);
});We're not using a DOM <form> so you can see Lynxt.ts can be used even if you don't have those kind of elements. Notice how defining the fields is very similar for these two text fields. We recommend creating your own field abstractions to avoid repetition. You can also take a look into @lynxts/web and/or @lynxts/native, we're you can find the most common abstractions, like a <Form> componenent for the DOM, simple fields, and submit-like components for React Native.
Accessing the form state
Occasionally you'll need to conditionally render something in your form based on the state of the fields. You can access the state in either two ways:
Move the form children to a separate component so you can access the form context with
useForm<T>()hook, or better yetuseFormSelector<T>(ctxt => ctxt.values).Use the render prop children of
<FormProvider>which gives access to some parts if the form context.
There's no specially better option here, it may depend on your use case. However, keep in mind that the children of <FormProvider> is well memoized, so if you want to avoid unnecessary re-renders, always use React.memo to create the components that will be part of the form (or for every component, which is better yet 😉).
Custom fields
Even though @lynxts/web and @lynxts/native provide abstractions of the most common fields on each environment, most of the time you'd want to use custom field components which may even come from any UI library, like Blueprint.js, MateriaUI, Ant Design, React Native Paper, etc. To use custom fields we provide 2 options:
1. Hooks + Field abstraction (recommended)
This option consists on creating your own abstraction of the custom field component. This is the recommended way because of some benefits:
The custom field becomes reusable.
Better memoization to prevent unnecessary renders
Delegate and standarize labels, a11y, validation messages, etc.
2. Field helper component
The <Field /> component is based on render props to provide the same hooks values to render a custom component. Even though this approach may look simpler, it comes with some tradeoffs:
Render props never have a stable reference to themselves, so they re-render every time something changes.
To avoid this problem,
<Field />memoiazes the result of the render props.The component provides a
depsprops which allows the user to add external dependencies that should cause a re-rerender when changed.Components inside the render prop should be memoized, or they'll re-render either way.
Dynamic array field
It's not uncommon for a form to have dynamic field that can be added or removed by the user. To to make this problem simpler, Lynx.ts provides the useArrayField(..) hook and the <ArrayField /> component, which is just an abstraction of the hook which uses render props to give access its values. These two provide well-memoized helper functions to work with dynamic array fields, like append(..), keygen(..), remove(..), replace(..), etc. With also access to the array items state, which shall be used to iterate over and render the fields dynamically.
Just like the
<Field>component,<ArrayField>also memoizes the result of the children render prop to avoid unnecessary renders. You can pass more dependencies on thedepsprop to control when to re-render. For better results, always useReact.memoon the componets used on render props.
Validation adapters
Lynx.ts works out-of-the-box with both Yup and Zod schemas, but if you'd prefer to use a different library, you need only to implement an Adapter<T> which tells Lynx.ts how the validation should work.
An Adapter<T> consist on implementing three function:
required: A function that tells if a field in a path is required or not.
validate: A function used to validate the Form values against a schema.
validateAt: A function used to validate a single field value in a path.
The validation prop accepts either a Yup/Zod schema or a custom adapter, so you could create an function that creates an adapter from your especific schema:
Bypass validation
If you wish not use any validation at all, Lynx.ts provides a noValidate() adapter you can use for this purpose.
API Reference
You can find the complete API refence here 📚
Something's missing?
Suggestions are always welcome! Please create an issue describing the request, feature, or bug. We'll try to look into it as soon as possible 🙂
Contributions
Contributions are very welcome! To do so, please fork this repository and open a Pull Request to the main branch.
License
Last updated
Was this helpful?