React TypeScript中Material UI Switch绑定onChange报错如何解决
问题核心原因
- 类型不匹配:你封装的
SwitchWithLabel组件向外传递的onChange回调参数是自定义的{name, checked}结构,不是原生的React.ChangeEvent<HTMLInputElement>事件对象,和你外层定义的回调参数类型冲突。 - 隐藏逻辑BUG:
SwitchWithLabel内部给Switch组件传参时,先写了内部的onChange逻辑再透传外部属性,会导致外部传入的onChange覆盖内部的表单状态更新逻辑,造成表单值不同步。 - 冗余状态:你同时用React Hook Form的Controller托管表单状态和本地
useState维护开关状态,容易出现两边状态不一致的问题,属于不必要的重复维护。
修复方案
第一步:修改SwitchWithLabel组件逻辑
调整参数透传顺序,兼容参数类型,同时保证内部表单更新逻辑不被覆盖:
export const SwitchWithLabel = <T extends string = string>({ label, name, control, ...switchProps }: SwitchWithLabelProps<T>) => { const styles = useStyles(); return ( <Controller name={name} control={control} render={({ value, onChange }) => ( <FormControlLabel className={styles.label} label={label} control={ <Switch name={name} // 先透传外部属性,避免内部逻辑被覆盖 {...switchProps} onChange={async (eventOrProps) => { // 兼容原生事件和自定义参数两种场景 const checked = 'target' in eventOrProps ? eventOrProps.target.checked : eventOrProps.checked; // 先执行外部传入的自定义回调 if (switchProps.onChange) { await switchProps.onChange({ name, checked }); } // 更新表单托管的状态 onChange(checked); }} checked={value} /> } /> )} /> ); };
第二步:简化VirtualEventSection组件逻辑
直接从表单托管状态读取开关值,去掉冗余的本地状态和回调:
import { useWatch } from 'react-hook-form'; // 引入useWatch读取表单状态 export const VirtualEventSection = ({ control, onSearch, onSearchInputChange, searchInputValue, }: VirtualEventSectionProps) => { const { formatMessage } = useLocale(); const styles = useStyles(); // 直接读取表单中的virtualEnabled值,自动同步状态 const isVirtualEnabled = useWatch({ control, name: 'virtualEnabled', defaultValue: false }); return ( <Card className={styles.actionCard}> <Grid container spacing={1} alignItems="flex-start"> <Grid item sm={12} xs={12}> <SwitchWithLabel name="virtualEnabled" label={formatMessage({ id: 'form_event.event_toggle_lable' })} control={control} /> {/* 简化条件渲染,无需多余的空节点占位 */} {isVirtualEnabled && ( <LocationSelection control={control} onSearch={onSearch} onSearchInputChange={onSearchInputChange} searchInputValue={searchInputValue} /> )} </Grid> </Grid> </Card> ); };
修改完成后即可解决类型报错,同时实现开关控制组件显隐的需求,表单状态和显隐状态完全同步,不会出现不一致问题。
内容的提问来源于stack exchange,提问作者user17112368
相关产品推荐
相关产品推荐

