Top Related Projects
Build forms in React, without the tears 😭
📋 React Hooks for form state management and validation (Web + React Native)
🏁 High performance subscription-based form state management for React
A Higher Order Component using react-redux to keep form state in a Redux store
Performance-focused API for React forms 🚀
Quick Overview
React-component/form is a high-performance, flexible, and extensible form library for React applications. It provides a set of components and utilities to handle form state management, validation, and submission with ease, while offering advanced features like field arrays and nested forms.
Pros
- Highly performant, with optimized re-rendering
- Extensive API with support for complex form scenarios
- Well-documented and actively maintained
- Seamless integration with React ecosystem
Cons
- Steeper learning curve compared to simpler form libraries
- Can be overkill for basic form needs
- Requires additional setup for certain advanced features
- Some users report occasional issues with TypeScript definitions
Code Examples
- Basic form setup:
import { Form, Field } from 'rc-field-form';
const MyForm = () => (
<Form onFinish={values => console.log(values)}>
<Field name="username" rules={[{ required: true }]}>
<input />
</Field>
<button type="submit">Submit</button>
</Form>
);
- Using custom validators:
import { Form, Field } from 'rc-field-form';
const MyForm = () => (
<Form>
<Field
name="email"
rules={[
{ required: true },
{ type: 'email' },
{ validator: async (_, value) => {
if (value && !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)) {
throw new Error('Invalid email address');
}
}}
]}
>
<input />
</Field>
</Form>
);
- Handling nested fields:
import { Form, Field } from 'rc-field-form';
const MyForm = () => (
<Form>
<Field name={['user', 'name']}>
<input />
</Field>
<Field name={['user', 'email']}>
<input type="email" />
</Field>
</Form>
);
Getting Started
To use react-component/form in your project:
-
Install the package:
npm install rc-field-form
-
Import and use in your React component:
import { Form, Field } from 'rc-field-form'; const MyForm = () => ( <Form onFinish={values => console.log(values)}> <Field name="username" rules={[{ required: true }]}> <input /> </Field> <button type="submit">Submit</button> </Form> );
-
Customize as needed, adding more fields, validation rules, and form logic to suit your application's requirements.
Competitor Comparisons
Build forms in React, without the tears 😭
Pros of Formik
- More comprehensive form management solution with built-in validation, error handling, and form submission
- Simpler API and less boilerplate code required for common form scenarios
- Better integration with React ecosystem and hooks
Cons of Formik
- Steeper learning curve for developers new to the library
- May be overkill for simple form implementations
- Less flexibility for custom form layouts compared to Form
Code Comparison
Form:
<Form onSubmit={this.onSubmit}>
{({ getFieldDecorator }) => (
<Form.Item>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(<Input placeholder="Username" />)}
</Form.Item>
)}
</Form>
Formik:
<Formik
initialValues={{ username: '' }}
onSubmit={this.onSubmit}
validationSchema={Yup.object().shape({
username: Yup.string().required('Please input your username!'),
})}
>
{({ errors, touched }) => (
<Form>
<Field name="username" placeholder="Username" />
{errors.username && touched.username && <div>{errors.username}</div>}
</Form>
)}
</Formik>
📋 React Hooks for form state management and validation (Web + React Native)
Pros of react-hook-form
- Lightweight and performant, with minimal re-renders
- Easy integration with existing forms and custom inputs
- Built-in validation and error handling
Cons of react-hook-form
- Less opinionated structure, which may require more setup for complex forms
- Limited built-in UI components compared to rc-form
Code Comparison
react-hook-form:
import { useForm } from "react-hook-form";
function App() {
const { register, handleSubmit } = useForm();
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<input type="submit" />
</form>
);
}
rc-form:
import { createForm } from 'rc-form';
class Form extends React.Component {
submit = () => {
this.props.form.validateFields((error, value) => {
console.log(error, value);
});
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<form onSubmit={this.submit}>
{getFieldDecorator('firstName')(<input />)}
{getFieldDecorator('lastName')(<input />)}
<button type="submit">Submit</button>
</form>
);
}
}
export default createForm()(Form);
The main difference is that react-hook-form uses hooks and functional components, while rc-form uses class components and higher-order components. react-hook-form's API is more concise and modern, while rc-form provides a more structured approach to form management.
🏁 High performance subscription-based form state management for React
Pros of react-final-form
- More lightweight and performant, with a smaller bundle size
- Better support for complex form structures and nested fields
- Offers a more flexible API with powerful validation and submission handling
Cons of react-final-form
- Steeper learning curve for developers new to the library
- Less comprehensive documentation compared to react-component/form
- Fewer pre-built form components, requiring more custom implementation
Code Comparison
react-component/form:
import { Form, Input } from 'rc-form';
const MyForm = ({ form }) => (
<Form onSubmit={handleSubmit}>
<Form.Item>
{form.getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(<Input />)}
</Form.Item>
</Form>
);
react-final-form:
import { Form, Field } from 'react-final-form';
const MyForm = () => (
<Form onSubmit={handleSubmit}>
{({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="username" validate={required}>
{({ input, meta }) => (
<div>
<input {...input} />
{meta.error && meta.touched && <span>{meta.error}</span>}
</div>
)}
</Field>
</form>
)}
</Form>
);
A Higher Order Component using react-redux to keep form state in a Redux store
Pros of redux-form
- Seamless integration with Redux state management
- Powerful form validation and normalization features
- Extensive documentation and community support
Cons of redux-form
- Steeper learning curve for developers new to Redux
- Can be overkill for simple form implementations
- Performance concerns with large forms due to frequent re-renders
Code Comparison
redux-form:
import { reduxForm, Field } from 'redux-form';
const SimpleForm = ({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="firstName" component="input" type="text" />
<button type="submit">Submit</form>
</form>
);
export default reduxForm({ form: 'simple' })(SimpleForm);
react-component/form:
import { createForm } from 'rc-form';
const SimpleForm = ({ form }) => (
<form onSubmit={form.submit}>
<input {...form.getFieldProps('firstName')} />
<button type="submit">Submit</button>
</form>
);
export default createForm()(SimpleForm);
Both libraries provide form management solutions for React applications, but they differ in their approach and complexity. redux-form is more feature-rich and integrates tightly with Redux, while react-component/form offers a simpler, more lightweight solution that doesn't require Redux. The choice between the two depends on the project's requirements, team expertise, and desired level of form management complexity.
Performance-focused API for React forms 🚀
Pros of Unform
- More lightweight and performant, with a focus on uncontrolled components
- Better TypeScript support and type inference
- Easier integration with React Native projects
Cons of Unform
- Less mature and smaller community compared to Form
- Fewer pre-built form components and validations out of the box
- Steeper learning curve for developers used to traditional form libraries
Code Comparison
Form:
import { Form, Input } from 'rc-form';
const MyForm = ({ form }) => (
<Form>
<Input name="username" />
<button type="submit">Submit</button>
</Form>
);
export default Form.create()(MyForm);
Unform:
import { Form } from '@unform/web';
import Input from './Input';
const MyForm = () => (
<Form onSubmit={handleSubmit}>
<Input name="username" />
<button type="submit">Submit</button>
</Form>
);
export default MyForm;
The main difference is that Unform uses a more modern, hooks-based approach, while Form relies on higher-order components. Unform's implementation is generally more concise and doesn't require wrapping the component with a create function.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
rc-form
React High Order Form Component.
Development
npm install
npm start
open http://localhost:8000/examples/
Feature
- Support react.js and even react-native
- Validate fields with async-validator
Install
Usage
import { createForm, formShape } from 'rc-form';
class Form extends React.Component {
static propTypes = {
form: formShape,
};
submit = () => {
this.props.form.validateFields((error, value) => {
console.log(error, value);
});
}
render() {
let errors;
const { getFieldProps, getFieldError } = this.props.form;
return (
<div>
<input {...getFieldProps('normal')}/>
<input {...getFieldProps('required', {
onChange(){}, // have to write original onChange here if you need
rules: [{required: true}],
})}/>
{(errors = getFieldError('required')) ? errors.join(',') : null}
<button onClick={this.submit}>submit</button>
</div>
);
}
}
export createForm()(Form);
Use with React Native
Expo preview
Or a quicker version:
import { createForm } from 'rc-form';
class Form extends React.Component {
componentWillMount() {
this.requiredDecorator = this.props.form.getFieldDecorator('required', {
rules: [{required: true}],
});
}
submit = () => {
this.props.form.validateFields((error, value) => {
console.log(error, value);
});
}
render() {
let errors;
const { getFieldError } = this.props.form;
return (
<div>
{this.requiredDecorator(
<input
onChange={
// can still write your own onChange
}
/>
)}
{(errors = getFieldError('required')) ? errors.join(',') : null}
<button onClick={this.submit}>submit</button>
</div>
);
}
}
export createForm()(Form);
createForm(option: Object) => (WrappedComponent: React.Component) => React.Component
Option | Description | Type | Default |
---|---|---|---|
option.validateMessages | Preseted messages of async-validator | Object | {} |
option.onFieldsChange | Called when field changed, you can dispatch fields to redux store. | (props, changed, all): void | NOOP |
option.onValuesChange | Called when value changed. | (props, changed, all): void | NOOP |
option.mapProps | Get new props transferred to WrappedComponent. | (props): Object | props => props |
option.mapPropsToFields | Convert value from props to fields. Used for read fields from redux store. | (props): Object | NOOP |
option.fieldNameProp | Where to store the name argument of getFieldProps . | String | - |
option.fieldMetaProp | Where to store the meta data of getFieldProps . | String | - |
option.fieldDataProp | Where to store the field data | String | - |
option.withRef(deprecated) | Maintain an ref for wrapped component instance, use refs.wrappedComponent to access. | boolean | false |
Note: use wrappedComponentRef instead of withRef after rc-form@1.4.0
class Form extends React.Component { ... }
// deprecated
const EnhancedForm = createForm({ withRef: true })(Form);
<EnhancedForm ref="form" />
this.refs.form.refs.wrappedComponent // => The instance of Form
// Recommended
const EnhancedForm = createForm()(Form);
<EnhancedForm wrappedComponentRef={(inst) => this.formRef = inst} />
this.formRef // => The instance of Form
(WrappedComponent: React.Component) => React.Component
The returned function of createForm(). It will pass an object as prop form
with the following members to WrappedComponent:
getFieldProps(name, option): Object { [valuePropName], [trigger], [validateTrigger] }
Will create props which can be set on a input/InputComponent which support value and onChange interface.
After set, this will create a binding with this input.
<form>
<input {...getFieldProps('name', { ...options })} />
</form>
name: String
This input's unique name.
option: Object
Option | Description | Type | Default |
---|---|---|---|
option.valuePropName | Prop name of component's value field, eg: checkbox should be set to checked ... | String | 'value' |
option.getValueProps | Get the component props according to field value. | (value): Object | (value) => ({ value }) |
option.getValueFromEvent | Specify how to get value from event. | (e): any | See below |
option.initialValue | Initial value of current component. | any | - |
option.normalize | Return normalized value. | (value, prev, all): Object | - |
option.trigger | Event which is listened to collect form data. | String | 'onChange' |
option.validateTrigger | Event which is listened to validate. Set to falsy to only validate when call props.validateFields. | String | String[] |
option.rules | Validator rules. see: async-validator | Object[] | - |
option.validateFirst | Whether stop validate on first rule of error for this field. | boolean | false |
option.validate | Object[] | - | |
option.validate[n].trigger | Event which is listened to validate. Set to falsy to only validate when call props.validateFields. | String | String[] |
option.validate[n].rules | Validator rules. see: async-validator | Object[] | - |
option.hidden | Ignore current field while validating or gettting fields | boolean | false |
option.preserve | Whether to preserve the value. That will remain the value when the field be unmounted and be mounted again | boolean | false |
Default value of getValueFromEvent
function defaultGetValueFromEvent(e) {
if (!e || !e.target) {
return e;
}
const { target } = e;
return target.type === 'checkbox' ? target.checked : target.value;
}
Tips
{
validateTrigger: 'onBlur',
rules: [{required: true}],
}
// is the shorthand of
{
validate: [{
trigger: 'onBlur',
rules: [{required: true}],
}],
}
getFieldDecorator(name:String, option: Object) => (React.Node) => React.Node
Similar to getFieldProps
, but add some helper warnings and you can write onXX directly inside React.Node props:
<form>
{getFieldDecorator('name', otherOptions)(<input />)}
</form>
getFieldsValue([fieldNames: String[]])
Get fields value by fieldNames.
getFieldValue(fieldName: String)
Get field value by fieldName.
getFieldInstance(fieldName: String)
Get field react public instance by fieldName.
setFieldsValue(obj: Object)
Set fields value by kv object.
setFieldsInitialValue(obj: Object)
Set fields initialValue by kv object. use for reset and initial display/value.
setFields(obj: Object)
Set fields by kv object. each field can contain errors and value member.
validateFields([fieldNames: String[]], [options: Object], callback: (errors, values) => void)
Validate and get fields value by fieldNames.
options is the same as validate method of async-validator.
And add force
.
options.force: Boolean
Defaults to false. Whether to validate fields which have been validated(caused by validateTrigger).
getFieldsError(names): Object{ [name]: String[] }
Get inputs' validate errors.
getFieldError(name): String[]
Get input's validate errors.
isFieldValidating(name: String): Bool
Whether this input is validating.
isFieldsValidating(names: String[]): Bool
Whether one of the inputs is validating.
isFieldTouched(name: String): Bool
Whether this input's value had been changed by user.
isFieldsTouched(names: String[]): Bool
Whether one of the inputs' values had been changed by user.
resetFields([names: String[]])
Reset specified inputs. Defaults to all.
isSubmitting(): Bool (Deprecated)
Whether the form is submitting.
submit(callback: Function) (Deprecated)
Cause isSubmitting to return true, after callback called, isSubmitting return false.
rc-form/lib/createDOMForm(option): Function
createDOMForm enhancement, support props.form.validateFieldsAndScroll
validateFieldsAndScroll([fieldNames: String[]], [options: Object], callback: (errors, values) => void)
props.form.validateFields enhancement, support scroll to the first invalid form field, scroll
is the same as dom-scroll-into-view's function parameter config
.
options.container: HTMLElement
Defaults to first scrollable container of form field(until document).
Notes
-
Do not use stateless function component inside Form component: https://github.com/facebook/react/pull/6534
-
you can not set same prop name as the value of validateTrigger/trigger for getFieldProps
<input {...getFieldProps('change',{
onChange: this.iWantToKnow // you must set onChange here or use getFieldDecorator to write inside <input>
})}>
- you can not use ref prop for getFieldProps
<input {...getFieldProps('ref')} />
this.props.form.getFieldInstance('ref') // use this to get ref
or
<input {...getFieldProps('ref',{
ref: this.saveRef // use function here or use getFieldDecorator to write inside <input> (only allow function)
})} />
Test Case
npm test
npm run chrome-test
Coverage
npm run coverage
open coverage/ dir
License
rc-form is released under the MIT license.
Top Related Projects
Build forms in React, without the tears 😭
📋 React Hooks for form state management and validation (Web + React Native)
🏁 High performance subscription-based form state management for React
A Higher Order Component using react-redux to keep form state in a Redux store
Performance-focused API for React forms 🚀
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot