React Hook中checkErrors返回值与内部输出不一致问题求助
函数内部输出与外部返回值不一致问题
问题描述
调用checkErrors函数时,函数内部console.log输出结果为[{ foo: 'bar'}],但外部接收返回值时得到的是空数组[],调用发生在包含useState的React Hook(useField)中,完全不清楚不一致的原因。
伪代码示例:
// 实际调用的函数示例,伪代码便于理解问题 const checkErrors = (input) => { const data = invokeCheckFunction(input) console.log('wtf ==>', data) // [{ foo: 'bar'}] return data }
调用方代码:
const test = checkErrors(myInput) console.log('why is it empty', test) // []
调用方仅使用了useState,找不到这种莫名不同步的原因。
错误检查相关代码
错误检查内部处理函数
import type { CheckFunction, Config, FieldError } from '../types' type ErrorWithInternal<T, E = Error> = { INTENRAL_IS_ERROR: true } & FieldError<T, E> export const invokeCheckFunction = <T, C extends CheckFunction<T>, E = Error>( value: T, name: string, checkFunction: C, ) => { let result: ReturnType<C> | ErrorWithInternal<T, E> try { result = checkFunction(value) } catch (error) { const fieldError: ErrorWithInternal<T, E> = { error: error as E, message: (error as Error)?.message, name, value, INTENRAL_IS_ERROR: true, } result = fieldError } return result }
主处理函数
const isError = <T, C extends CheckFunction<T>, E = Error>( error: ErrorWithInternal<T, E> | ReturnType<C>, ): error is ErrorWithInternal<T, E> => !!(error as ErrorWithInternal<T, E>)?.INTENRAL_IS_ERROR const isPassed = <T, C extends CheckFunction<T>, E = Error>( error: ErrorWithInternal<T, E> | ReturnType<C>, ): error is ReturnType<C> => !isError(error) export const checkErrors = <T, C extends CheckFunction<T>, E = Error>( value: T, name: string, checkFunctions: C[], ): [FieldError<T, E>[], ReturnType<C>[]] => { const results = checkFunctions.map((checkfn) => invokeCheckFunction<T, C, E>(value, name, checkfn), ) const internalErrors: ErrorWithInternal<T, E>[] = results.filter((e) => isError(e)) const passed = results.filter((e) => isPassed(e)) as ReturnType<C>[] const errors: FieldError<T, E>[] = internalErrors.map((e) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { INTENRAL_IS_ERROR, ...rest } = e return rest as FieldError<T, E> }) console.log('wtf => ', errors, passed) return [errors, passed] }
问题发生的Hook逻辑
export const useField = <T, E = Error, C extends CheckFunction<T> = CheckFunction<T>>( name: string, initialValue: T, configOrCheckFunction?: C | Partial<Config>, ...checkFunctions: C[] ) => { const [value, setValue] = useState<T>(initialValue) // 注意:这不是useState,避免混淆语法 const [initialErrors, initialCheckResults] = checkErrors<T, C, E>(value, name, checks, config) const [errors, setErrors] = useState<FieldError<T, E>[]>(initialErrors) const [checkResults, setCheckResults] = useState(initialCheckResults) const onChange = (event: ChangeEvent<HTMLInputElement>) => { const { value: newVal } = event.target const [newErrors, newChecked] = checkErrors<T, C, E>( newVal as T, name, checkFunctions, ) console.log('why is it empty', newErrors) setErrors(newErrors) setValue(newVal) } }
为了可读性省略了无关代码,核心逻辑如上,找不到问题原因。
测试用React应用代码
import { useField } from 'eformless' const App = () => { // 示例错误处理函数 const nonEmpty = (val: string) => { if (val.length === 0) { throw new Error('Cannot be empty') } return val } const test = useField('example', '', nonEmpty) return ( <input name={test.name} value={test.value} onChange={test.onChange} /> ) }

内容的提问来源于stack exchange,提问作者Samuel Hulla
相关产品推荐
相关产品推荐

