• First, there is the React component in the form
    • The controlled components
    • Uncontrolled component
function MyForm() {

    const [value, setValue] = useState(' ')

    const handleChange = (evt) = > {

        setValue(evt.target.value)

    }

    return <input value={value} onChange={this.handleChange} />

}
Copy the code

Controlled components. The state of a form component is fully controlled by React, but frequent updates to the state can cause performance problems

function MyForm() {

    const inputRef = useRef()

    const handleSubmit = (evt) = > {

        // Use prevetnDefault to prevent pages from being refreshed

        evt.preventDefault()

        alert(inputRef.current.value)

    }
   
    return (

        <form onSubmit={handleSubmit}>

            <label>

                Name:

                <input ref={inputRef} />

            </label>

            <input type="submit" value="Submit" />

        </form>)}Copy the code

Uncontrolled components, where the value of a form element is not determined by the parent component, but is a completely internal state.

As you can see, the input process has no effect on the overall state of the component, and does not result in a re-rendering of the component.

Simplify form processing with Hooks

Previously, for controlled components, follow these two steps:

  • Set a State to bind to the value of the form element
  • Listen for the onChange event of the form element to synchronize the form value to State

That is, maintaining the state logic of a form component has three core parts:

  • Field name
  • Binding the value value
  • Handle the onChange event

Since the logic is the same for each form element, we can reuse the logic using hooks

  • Use hooks to maintain the entire form. Use root names to set values or modify them

Basic implementation:

const useForm = (initialValues = {}) = > {

    // Set the status of the entire form to values

    const [values, setValues] = useState(initialValues)

    const setFieldValue = useCallback((name,value) = > {

        setValues((value) = > return {

            ...values,

            [name]: value

        })

    }, [])

    return { values, setFieldValue }

}
Copy the code

When using:

// ...

const [values, setFieldValues] = useForm()

// ...

<input value={values.name || null} onChange={setFieldValues('name',evt.target.value)} />

<input value={values.email || null} onChange={setFieldValues('email', evt.target.value)} / >
Copy the code

Most open source forms solutions are based on a core principle: separate form state management into a reusable Hook.

  • Handling form validation
    • Add one more essential logic for form processing: form validation

Follow the same state-driven principle:

  • First: How do you define such an error state
  • Second: how to set the error state

Add the API interface to the existing useForm Hook:

// Provide a validators object that provides validation functions for a field

const useForm = (initialValues = {}, validators) = > {

    const [values,setValues] = useState(initialValues)

    // Defines the errors state

    const [errors, setErrors] = useState({})

    const setFieldValue = useCallback((name, value) = >{ setValues(({ ... values, [name]: value }))// Call a validation function to validate user input

        if (validators[name]) {

            const errMsg = validators[name](value)

            setErrors((errors) = > ({

                ...errors,

                [name]: errMsg || null

            }))

        }

    },[validators])

    return { values, errors, setFieldValue }

}
Copy the code