@conform-to/react
Version:
Conform view adapter for react
92 lines (86 loc) • 2.69 kB
JavaScript
/**
* A memoized function with cache clearing capability.
*/
/**
* Default equality check that compares arguments using Object.is().
*
* @param prevArgs - Previous function arguments
* @param nextArgs - Current function arguments
* @returns True if all arguments are equal
*/
function defaultEqualityCheck(prevArgs, nextArgs) {
if (prevArgs.length !== nextArgs.length) {
return false;
}
for (var i = 0; i < prevArgs.length; i++) {
if (!Object.is(prevArgs[i], nextArgs[i])) {
return false;
}
}
return true;
}
/**
* Memoizes function calls, caching only the most recent result to prevent redundant async validations.
*
* Built-in implementation based on memoize-one with enhanced async support.
* Can be replaced with other memoization libraries if needed.
*
* @param fn - The function to memoize
* @param isEqual - Custom equality function to compare arguments (defaults to shallow comparison)
* @returns Memoized function with cache clearing capability
*
* @example
* ```ts
* // Async validation with API call
* const validateUsername = useMemo(
* () => memoize(async function isUnique(username: string) {
* const response = await fetch(`/api/users/${username}`);
* return response.ok ? null : ['Username is already taken'];
* }),
* []
* );
*
* // Usage in form validation
* async onValidate({ payload, error }) {
* if (payload.username && !error.fieldErrors.username) {
* const messages = await validateUsername(value.username);
* if (messages) error.fieldErrors.username = messages;
* }
* return error;
* }
* ```
*/
function memoize(fn) {
var isEqual = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultEqualityCheck;
var cache = null;
function memoized() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
// Check if new arguments match last arguments including the context (this)
if (cache && cache.this === this && isEqual(cache.args, args)) {
return cache.result;
}
var result = fn.apply(this, args);
if (result instanceof Promise) {
result = result.catch(e => {
// If the promise is rejected, clear the cache so that the next call will re-invoke fn
cache = null;
// Re-throw the exception so that it can be handled by the caller
throw e;
});
}
// Update the cache
cache = {
this: this,
args,
result
};
return result;
}
memoized.clearCache = function clearCache() {
cache = null;
};
return memoized;
}
export { defaultEqualityCheck, memoize };