feat: optimizes field performance by storing internal values in useField hook

This commit is contained in:
James
2022-11-12 18:46:31 -05:00
parent 2f684040fc
commit 66210b856b

View File

@@ -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;
};