@effijs/form-react
v2.0.10
Published
An efficient, modern way to organize the business logic of an application(@effijs/form-react)
Downloads
149
Readme
Introduction
@effijs/form-react is a powerful React form library built on top of the Store.Form module from @effijs/common.
This library provides a comprehensive solution for handling form state, validation, and complex nested data structures
in React applications.
It offers a declarative API to build forms with minimal boilerplate code. It efficiently manages form state, handles field dependencies, and provides utilities for data validation and manipulation.
The library adopts a component-based approach where forms are composed of various specialized components, each serving a specific purpose in the form structure hierarchy.
Core Components
Form
The main container component that establishes the form context and manages the form state.
Props:
Store.Form: The form store instance from@effijs/commonchildren: React elements representing form content
Usage:
import {useMemo} from 'react';
import {Form} from '@effijs/form-react';
import {Store, Validator} from '@effijs/common';
@Validator.Decorators.Options({
skipMissingProperties: true,
})
class FormDataValidator {
@Validator.Decorators.Property()
@Validator.Decorators.Validator(
(value) => value.length >= 2,
"Title must be at least 2 characters long",
)
title?: string;
...
}
const MyForm = ({initial}: {initial: any}) => {
const formStore = useMemo(() => new Store.Form(initial, FormDataValidator), []);
const handleSubmit = () => {
const {validated, error} = store.validate();
if (error) {
return error
}
console.log(validated);
};
return (
<>
<Form store={formStore}>
{/* Form fields go here */}
</Form>
<button onClick={handleSubmit}>Submit</button>
</>
);
};Form.Item
A component that connects a form field to the form store.
Props:
name: Field name (path) in the form stateinitial: Optional initial value for the fieldchildren: The form field component to renderdeps: Optional dependencies that should trigger re-render and passes to component
Usage:
<Form.Item name="confirm-password" initial="" deps={['password']}>
<input type="text"/>
</Form.Item>Form.Obj
A component for handling nested object structures in forms.
Props:
name: Object name (path) in the form statechildren: React nodes representing nested form fields
Usage:
<Form.Obj name="address">
<Form.Item name="street">
<input type="text"/>
</Form.Item>
<Form.Item name="city">
<input type="text"/>
</Form.Item>
</Form.Obj>Form.List
A component for handling array structures in forms.
Props:
name: Array name (path) in the form statechildren: Template for array itemskeyExtractor: Optional function to extract unique keys for list items
Usage:
<Form.List name="contacts">
<AddDeleteActions>
<Form.Item name="name">
<input type="text"/>
</Form.Item>
<Form.Item name="phone">
<input type="text"/>
</Form.Item>
</AddDeleteActions>
</Form.List>
function AddDeleteActions({
onAdd, onRemove, children, isLast, isFirst,
}: {
onAdd?: () => void;
onRemove?: () => void;
children?: React.ReactNode;
isLast?: boolean;
isFirst?: boolean;
}) {
return (
<>
{children}
{/* Actions go here */}
</>
);
}Form.Data
A component for accessing form data and errors within the component tree.
Props:
children: React element that can access form data
Usage:
<Form.Data>
{({data, error}) => (
<div className={error.username ? 'error': ''}>
Current username: {data.username}
</div>
)}
</Form.Data>Form.Proxy
A component for sharing form context with components outside the form tree.
Props:
form: Form context objectchildren: React elements to receive the form context
Usage:
const {store} = Form.useForm();
// Later in component tree, possibly in a different component
<Form.Proxy form={{store}}>
<SomeComponent/>
</Form.Proxy>Form.CleanOnDestroy
A utility component that cleans up specified form fields when unmounted.
Props:
keys: Array of field names to clean up on component unmount
Usage:
<Form.CleanOnDestroy keys={['temporaryField']}>
<TemporaryFormSection/>
</Form.CleanOnDestroy>Form.DestroyWhen
A component that conditionally destroys form data based on a condition.
Props:
name: Field name in the form stateinitial: Optional initial valuechildren: React elementcondition: Function that determines when to destroy the field valuedeps: Optional dependencies that should trigger condition evaluation
Usage:
<Form.DestroyWhen
name="additionalInfo"
condition={(value, deps) => deps.includeAdditional === false}
deps={{includeAdditional: 'includeAdditional'}}
>
<textarea/>
</Form.DestroyWhen>Hooks
useForm
Hook for accessing a form store instance.
Returns:
store: Form store instance
Usage:
const MyForm = () => {
const {store} = Form.useForm();
// Use store methods like getValues(), setValues(), etc.
return <Form store={store}>{/* Form fields */}</Form>;
};useFormStore
Hook for accessing the current form store context.
Returns:
- Form store context
Usage:
const FormField = () => {
const formStore = useFormStore();
// Access form state, methods, etc.
return <div>{/* Field implementation */}</div>;
};Advanced Examples
Complex Nested Form
import {Form} from '@effijs/form-react';
import {Store} from '@effijs/common';
const ComplexForm = ({initial}) => {
const formStore = useMemo(() => new Store.Form(initial, FormDataValidator), []);
const handleSubmit = () => {
const {validated, error} = store.validate();
if (error) {
return error
}
console.log(validated);
};
return (
<>
<Form store={formStore}>
<div>
<h2>Personal Information</h2>
<Form.Item name="firstName" initial="">
<input placeholder="First Name"/>
</Form.Item>
<Form.Item name="lastName" initial="">
<input placeholder="Last Name"/>
</Form.Item>
<h2>Address</h2>
<Form.Obj name="address">
<Form.Item name="street" initial="">
<input placeholder="Street"/>
</Form.Item>
<Form.Item name="city" initial="">
<input placeholder="City"/>
</Form.Item>
<Form.Item name="zipCode" initial="">
<input placeholder="Zip Code"/>
</Form.Item>
</Form.Obj>
<h2>Contacts</h2>
<Form.List name="contacts">
<FormListActions>
<div style={{display: 'flex', gap: '10px', marginBottom: '10px'}}>
<Form.Item name="type" initial="email">
<select>
<option value="email">Email</option>
<option value="phone">Phone</option>
</select>
</Form.Item>
<Form.Item name="value" initial="">
<input placeholder="Contact Value"/>
</Form.Item>
</div>
</FormListActions>
</Form.List>
</div>
</Form>
<button onClick={handleSubmit}>Submit</button>
</>
);
};Summary
@effijs/form-react provides a flexible and powerful solution for building complex forms in React applications. Its
component-based approach allows for intuitive form structure definition while the underlying Store.Form from
@effijs/common efficiently manages the form state and validation.
Key features:
- Declarative API with reusable components
- Support for deeply nested objects and arrays
- Conditional form fields
- Form state access via hooks
- Clean-up utilities to prevent stale data
- Dependencies tracking for dynamic form behavior
By combining these building blocks, developers can create sophisticated forms with complex data structures while maintaining clean and maintainable code.
