SolidJS中FormContext无法传递给子组件问题求助
问题原因与修复方案
核心问题
你的代码中存在两个关键问题导致Context无法正确传递:
- FormContext默认值与实际值类型不匹配:创建Context时默认值的
data是普通对象,但实际传递给Provider的data是SolidJS Signal的Accessor函数,类型不匹配导致Context识别异常。 - InputText中错误访问Signal数据:直接用
form.data[name]访问Signal,而正确方式应该调用Accessor函数form.data()[name]。
修复步骤
1. 修正FormContext默认值与接口类型
在FormContextProvider.tsx中,调整Form接口和Context默认值,确保类型统一:
// 修正Form接口,明确data为Accessor类型 export interface Form { data: Accessor<FormData>; set: (data: FormData | ((prev: FormData) => FormData)) => void; validationResult: Accessor<Joi.ValidationResult<any> | undefined>; touched: Accessor<TouchedData>; setFieldValue: (field: string, value: string) => void; inputChangeHandler: (name: string) => (e: Event) => void; } // 修正Context默认值,data改为返回空对象的函数 export const FormContext = createContext<Form>({ data: () => ({}), set: () => undefined, validationResult: () => undefined, touched: () => ({}), setFieldValue: () => undefined, inputChangeHandler: () => () => undefined, });
2. 修正setFieldValue函数(避免覆盖表单数据)
在FormContextProvider.tsx的form对象中,修改setFieldValue为合并式更新:
setFieldValue: (field: string, value: string) => { setFormData(prev => ({ ...prev, [field]: value })); },
3. 修正initialTouchData初始化
在FormContextProvider.tsx中,将初始触摸数据改为空对象:
const initialTouchData: TouchedData = {};
4. 修正InputText中访问表单数据的方式
在InputText.tsx中,修改value的取值方式:
<input type={type} name={name} id={name} placeholder={label} value={form.data()[name] || ""} onInput={form.inputChangeHandler(name)} />
5. 验证Context导入路径
确保InputText.tsx中导入的FormContext与FormContextProvider.tsx导出的是同一个实例,检查导入路径是否正确:
import { FormContext } from "../FormContextProvider/FormContextProvider";
修正后的关键代码片段
FormContextProvider.tsx(核心部分)
// ...其他代码 export default function FormContextProvider(props: FormContextProviderProps) { const { children, initialData, validation, postValidation = defaultPostValidation } = props; const [formData, setFormData] = createSignal<FormData>(initialData || {}); const initialTouchData: TouchedData = {}; const [touched, setTouched] = createSignal<TouchedData>(initialTouchData); const [validationResult, setValidationResult] = createSignal<Joi.ValidationResult<any> | undefined>(); // ...validate函数保持不变 const form = { data: formData, set: setFormData, validationResult, touched, setFieldValue: (field: string, value: string) => { setFormData(prev => ({ ...prev, [field]: value })); }, inputChangeHandler: (name: string) => (e: Event) => { const target = e.target as HTMLInputElement; setFormData(prev => ({ ...prev, [name]: target.value })); setTouched(prev => ({ ...prev, [name]: true })); validate(); }, }; validate(); return ( <FormContext.Provider value={form}> <form use:formDecorator>{children}</form> </FormContext.Provider> ); }
InputText.tsx(核心部分)
export default function InputText(props: InputTextProps) { const { label, name, type } = props; const form = useContext(FormContext); if (!form) { return <div>FormContextProvider not found</div>; } const [error, setError] = createSignal(""); createEffect(() => { let updatedError = ""; const errorDetails = form.validationResult()?.error?.details; if (!errorDetails || !errorDetails.length) return setError(updatedError); errorDetails.forEach((error) => { if (error.context?.key === name) { updatedError = error.message; } }); setError(updatedError); }); return ( <div> <input type={type} name={name} id={name} placeholder={label} value={form.data()[name] || ""} onInput={form.inputChangeHandler(name)} /> <div class="error">{form.touched()[name] && error()} </div> </div> ); }
内容的提问来源于stack exchange,提问作者RobKohr
相关产品推荐
相关产品推荐

