Skip to content

React Native component to manage form and handle auto scroll form to error field

License

Notifications You must be signed in to change notification settings

egiwibowo13/rn-auto-scroll-form

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rn-auto-scroll-form

A Simple and fully customizable to handle Form in React Native. This library inspired by Formik.

Example

You can check Example code in this link

Features

  • Auto scroll to first error field
  • Manage, track state & values of fields
  • Supports validations using yup
  • Supports custom components

Getting Started

Installation

you can install using npm:

npm i rn-auto-scroll-form

Usage

Basic Usage

import { FormController } from 'rn-auto-scroll-form';

create validation using yup

  const schema = yup.object().shape({
    email: yup.string().email().required(),
    password: yup.string().min(6).required(),
  });
<FormController
  initialValue={{email: '', password: ''}}
  validationSchema={schema}
  onSubmit={({isValid, values, firstErrAt}) => console.warn(values)}>
{({
  values,
  errors,
  refs,
  handleChange,
  handleBlur,
  handleSubmit,
  }) => {
    return (
      <View style={styles.content}>
        <TextInput
          ref={refs?.email}
          style={styles.textInput}
          placeholder="Email"
          onChangeText={handleChange('email')}
          onBlur={handleBlur('email')}
          value={values?.email}
        />
        {!!errors.email && <Text>{errors.email}</Text>}
        <TextInput
          ref={refs?.password}
          style={styles.textInput}
          placeholder="Password"
          onChangeText={handleChange('password')}
          onBlur={handleBlur('password')}
          value={values?.password}
        />
        {!!errors.password && <Text style={styles.errText}>{errors.password}</Text>}
        <Button onPress={handleSubmit} title="Submit" />
      </View>
    );
  }}
</FormController>

Function useFormController

import { useFormController, ScrollableView, Field } from 'rn-auto-scroll-form';
  const schema = yup.object().shape({
    email: yup.string().email().required(),
    password: yup.string().min(6).required(),
  });

  const myform = useFormController({
    initialValues: initialValue,
    enableReinitialize: true,
    validationSchema: schema,
    onSubmit: ({isValid, values, firstErrAt}) => {
      console.log({isValid, values, firstErrAt});
    },
  });
<ScrollableView ref={myform?.controller}>
  <View style={styles.content}>
    <Text
      style={
        styles.title
      }>{`${myform?.count?.count}/${myform?.count?.total}`}</Text>
    <Field component={MyField} label="Email" name="email" form={myform} />
    <Field component={MyField} label="Password" name="password" form={myform} />

    ...

    <Button onPress={myform.handleSubmit} title="Submit" />
  </View>
</ScrollableView>

Custom Component

this is example of custom component, make sure your custom component have props onChangeText onBlur value error (optional)

export const MyField = props => {
  const {style, error, label, ...otherProps} = props;
  return (
    <>
      <Text>{label}</Text>
      <TextInput style={[styles.textInput, style]} {...otherProps} />
      {!!error && <Text style={styles.errText}>{error}</Text>}
    </>
  );
};
import { FormController, Field } from 'rn-auto-scroll-form';

you dont need to handle onChangeText, etc anymore. that is handle at Field Wrapper Component

<FormController
  initialValue={{email: '', password: ''}}
  validationSchema={schema}
  onSubmit={({isValid, values, firstErrAt}) => console.warn(values)}>
{({
  handleSubmit,
  }) => {
    return (
      <View style={styles.content}>
        <Field
          label="Email"
          placeholder="Input your email"
          name="name"
          component={MyField}
        />
        <Field
          label="Password"
          placeholder="Input your password"
          component={MyField}
        />
        <Button onPress={handleSubmit} title="Submit" />
      </View>
    );
  }}
</FormController>

Create Custom Wrapper Component

you can create wrapper component for your component that dont have props onChangeText onBlur value.

in this example you need to get all data with useContext(FormContext) and mapping to your custom component value errText onChangeValue.

make sure your custom component have props name or whatever your naming that prop (to handle getting specific data)

import { FormContext } from 'rn-auto-scroll-form';

export const YourWrapField = ({ component: Component, name, ...props }) => {
    const ctx = useContext(FormContext);
    return (
        <View style={{ width: '100%' }} ref={ctx?.refs[name]}>
            <Component
                value={ctx?.values[name]}
                errText={ctx?.errors[name]}
                onChangeValue={ctx?.handleChange(name)}
                {...props}
            />
        </View>
    )
}

API Reference

FormController

Props

Property Required Type Default
children yes ((context: FormContext) => React.ReactNode) -
initialValues yes Values -
validationSchema No `Schema (() => Schema)`
validateOnBlur No bool true
validateOnChange No bool false
enableReinitialize No bool false
countRequiredOnly No bool true
autoscroll No bool true
countingFields No Array[String] null

useFormController

Params when using useFormController

type UseFormParams<T> = {
  initialValues: T;
  validationSchema: any;
  onSubmit: (params: SubmitParams<T>) => void;
  countRequiredOnly?: boolean;
  countingFields?: string[];
  validateOnChange?: boolean;
  validateOnBlur?: boolean;
  enableReinitialize?: boolean;
  autoscroll?: boolean;
};

params onSubmit

type SubmitParams<T> = {
  isValid: boolean;
  values: GenericObj<T>;
  firstErrAt?: string | null;
};

FormContext

Form Context

interface FormContext<T> {
  values: T;
  errors?: T;
  count: Count;
  refs?: T;
  controller: React.Ref<ScrollableView>;
  handleChange: (txt: string) => void;
  handleBlur: (txt: string) => void;
  handleSubmit: (refs: T) => void;
}

interface Count {
  count: number;
  total: number;
}

Field

you can use TextInputProps at Field Component

Property Required Type
name yes string

Contributing

Pull requests are always welcome! Feel free to open a new GitHub issue for any changes that can be made.

Working on your first Pull Request? You can learn how from this free series How to Contribute to an Open Source Project on GitHub

Author

Egi Wibowo | egiwibowo13

License

MIT