feat: optimizes field performance by storing internal values in useField hook
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useFormProcessing, useFormSubmitted, useFormModified, useForm, useFormFields } from '../Form/context';
|
||||
import { Options, FieldType } from './types';
|
||||
@@ -26,11 +26,16 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
|
||||
const { getData, getSiblingData, setModified } = useForm();
|
||||
|
||||
const value = field?.value as T;
|
||||
const initialValue = field?.initialValue as T;
|
||||
const valid = typeof field?.valid === 'boolean' ? field.valid : true;
|
||||
const showError = valid === false && submitted;
|
||||
|
||||
// We store internal value to ensure that components react immediately
|
||||
// to any value changes, therefore preventing "cursor jump" that can be seen
|
||||
// if a user types quickly in an input
|
||||
const [internalValue, setInternalValue] = useState<T>(() => field?.value as T);
|
||||
const [internalInitialValue, setInternalInitialValue] = useState<T>(() => field?.initialValue as T);
|
||||
|
||||
// Method to return from `useField`, used to
|
||||
// update field values from field component(s)
|
||||
const setValue = useCallback((e, disableModifyingForm = false) => {
|
||||
@@ -42,6 +47,8 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
}
|
||||
}
|
||||
|
||||
setInternalValue(val);
|
||||
|
||||
dispatchField({
|
||||
type: 'UPDATE',
|
||||
path,
|
||||
@@ -61,12 +68,12 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
const result = useMemo(() => ({
|
||||
showError,
|
||||
errorMessage: field?.errorMessage,
|
||||
value,
|
||||
value: internalValue,
|
||||
formSubmitted: submitted,
|
||||
formProcessing: processing,
|
||||
setValue,
|
||||
initialValue,
|
||||
}), [field, processing, setValue, showError, submitted, value, initialValue]);
|
||||
}), [field, processing, setValue, showError, submitted, internalValue, initialValue]);
|
||||
|
||||
// Throttle the validate function
|
||||
useThrottledEffect(() => {
|
||||
@@ -77,7 +84,7 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
disableFormData,
|
||||
validate,
|
||||
condition,
|
||||
value,
|
||||
value: internalValue,
|
||||
valid: false,
|
||||
errorMessage: undefined,
|
||||
};
|
||||
@@ -90,7 +97,7 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
operation,
|
||||
};
|
||||
|
||||
const validationResult = typeof validate === 'function' ? await validate(value, validateOptions) : true;
|
||||
const validationResult = typeof validate === 'function' ? await validate(internalValue, validateOptions) : true;
|
||||
|
||||
if (typeof validationResult === 'string') {
|
||||
action.errorMessage = validationResult;
|
||||
@@ -107,7 +114,7 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
|
||||
validateField();
|
||||
}, 150, [
|
||||
value,
|
||||
internalValue,
|
||||
condition,
|
||||
disableFormData,
|
||||
dispatchField,
|
||||
@@ -120,6 +127,13 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
validate,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialValue !== internalInitialValue) {
|
||||
setInternalValue(initialValue);
|
||||
setInternalInitialValue(initialValue);
|
||||
}
|
||||
}, [initialValue, internalInitialValue]);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user