使用Switch语句渲染组件时TextInput按键输入异常问题
问题原因
核心问题是组件定义位置导致的实例重复创建:
- Step1被定义在AddProductModal组件内部,每次父组件因state更新(比如输入字符触发
setTitle)重渲染时,Step1会被重新定义为全新的组件类型。 - React会判定这是完全不同的组件,随即卸载旧的Step1实例并挂载新实例,导致TextInput丢失焦点、输入中断,表现为每输入一个字符就停止响应。
- 而直接调用
Step1()时,本质是在render阶段执行函数返回JSX,并非作为组件实例渲染,不会触发卸载/重建流程,因此无异常。
解决方案
方案1:将Step1移到父组件外部定义
把Step1抽离为独立组件,避免每次父组件重渲染时组件类型被重置:
// 抽离Step1到AddProductModal外部 const Step1 = ({ title, setTitle }) => ( <ScrollView> <View style={styles.InputContainer}> <Text style={{ fontFamily: 'Gilroy-SemiBold', fontSize: 18, marginTop: 30 }}>Title</Text> <TextInput allowFontScaling={false} value={title} onChangeText={(value) => setTitle(value)} style={styles.singleInput} /> </View> </ScrollView> ) export default function AddProductModal({isVisible, toggleModal, page, setPage}) { const [title, setTitle] = useState('') const getCurrentComponent = () => { switch (page) { case 1: return <Step1 title={title} setTitle={setTitle}/>; case 2: return <Step2/>; } ;} return ( <View> {getCurrentComponent()} </View> ) }
方案2:用useMemo缓存组件渲染结果
通过useMemo缓存getCurrentComponent的返回值,仅当page变化时重新生成组件:
import { useMemo } from 'react'; export default function AddProductModal({isVisible, toggleModal, page, setPage}) { const [title, setTitle] = useState('') const Step1 = () => ( <ScrollView> <View style={styles.InputContainer}> <Text style={{ fontFamily: 'Gilroy-SemiBold', fontSize: 18, marginTop: 30 }}>Title</Text> <TextInput allowFontScaling={false} value={title} onChangeText={(value) => setTitle(value)} style={styles.singleInput} /> </View> </ScrollView> ) const getCurrentComponent = useMemo(() => { switch (page) { case 1: return <Step1/>; case 2: return <Step2/>; } }, [page]); // 仅page变化时重新计算 return ( <View> {getCurrentComponent} </View> ) }
方案3:直接在render中使用条件渲染
跳过中间函数,直接在JSX中用条件判断渲染组件,逻辑更直观:
export default function AddProductModal({isVisible, toggleModal, page, setPage}) { const [title, setTitle] = useState('') const Step1 = () => ( <ScrollView> <View style={styles.InputContainer}> <Text style={{ fontFamily: 'Gilroy-SemiBold', fontSize: 18, marginTop: 30 }}>Title</Text> <TextInput allowFontScaling={false} value={title} onChangeText={(value) => setTitle(value)} style={styles.singleInput} /> </View> </ScrollView> ) return ( <View> {page === 1 && <Step1/>} {page === 2 && <Step2/>} </View> ) }
内容的提问来源于stack exchange,提问作者CodingJunkie
相关产品推荐
相关产品推荐

