You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中TextInput输入字符时失焦的问题排查与解决

问题:React Native TextInput输入字符后失去焦点

我按照React Native文档编写了一个绑定状态的TextInput组件,代码如下:

function NewItemView(): JSX.Element {
    const [text, setText] = useState("");
    const dispatch = useDispatch();

    const submitText = () => {
        dispatch(createRecord(text))
        setText("")
    }

    return (
        <View>
            <TextInput
                style={{
                    backgroundColor: '#eeeeff',
                    borderBottomColor: '#000000',
                    borderBottomWidth: 1,
                }}
                onChangeText={setText}
                value={text}
            />
            <Button
                title='Create new record'
                onPress={submitText}
            />
        </View>
    )
}

在iPhone模拟器中,每当我在文本输入框中输入一个字符,输入框就会失去焦点,必须重新点击才能继续输入。该视图的使用方式如下:

function TodoList(): JSX.Element {
    const state: State = useSelector((state: any) => state.list);
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(fetchList)
    }, [])

    return (
        <View>
            <NewItemView/>
            <FlatList 
                data={state.data}
                renderItem={({item}) => <ItemCell text={item.text} />}
            />
        </View>
    )
}

原因分析

最可能的问题是**NewItemView被嵌套定义在TodoList组件内部**(你贴的代码里是独立的,但实际代码可能存在嵌套)。每次TodoList重新渲染时,NewItemView都会被重新定义为一个全新的组件类型,React会卸载旧的组件实例并挂载新的,直接导致TextInput失去焦点。

另外,如果useSelector的选择器返回的状态每次都是新对象,会导致TodoList频繁重新渲染,虽然不会直接触发卸载,但也可能间接引发焦点丢失问题。

解决方案

  1. 将NewItemView移到TodoList外部独立定义
    这是最直接的解决方式,确保组件不会随父组件渲染被重复创建:
// 独立定义NewItemView,放在TodoList外部
function NewItemView(): JSX.Element {
    const [text, setText] = useState("");
    const dispatch = useDispatch();

    const submitText = () => {
        dispatch(createRecord(text))
        setText("")
    }

    return (
        <View>
            <TextInput
                style={{
                    backgroundColor: '#eeeeff',
                    borderBottomColor: '#000000',
                    borderBottomWidth: 1,
                }}
                onChangeText={setText}
                value={text}
            />
            <Button
                title='Create new record'
                onPress={submitText}
            />
        </View>
    )
}

function TodoList(): JSX.Element {
    const state: State = useSelector((state: any) => state.list);
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(fetchList)
    }, [])

    return (
        <View>
            <NewItemView/>
            <FlatList 
                data={state.data}
                renderItem={({item}) => <ItemCell text={item.text} />}
                keyExtractor={(item) => item.id} // 建议添加,优化FlatList性能
            />
        </View>
    )
}
  1. 若必须嵌套定义,用React.memo记忆组件
    如果因为某些原因必须把NewItemView放在TodoList内部,使用React.memo包裹组件,避免不必要的重新渲染和卸载:
function TodoList(): JSX.Element {
    const state: State = useSelector((state: any) => state.list);
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(fetchList)
    }, [])

    // 用React.memo包裹,记忆组件
    const NewItemView = React.memo(() => {
        const [text, setText] = useState("");
        const dispatch = useDispatch();

        const submitText = () => {
            dispatch(createRecord(text))
            setText("")
        }

        return (
            <View>
                <TextInput
                    style={{
                        backgroundColor: '#eeeeff',
                        borderBottomColor: '#000000',
                        borderBottomWidth: 1,
                    }}
                    onChangeText={setText}
                    value={text}
                />
                <Button
                    title='Create new record'
                    onPress={submitText}
                />
            </View>
        )
    })

    return (
        <View>
            <NewItemView/>
            <FlatList 
                data={state.data}
                renderItem={({item}) => <ItemCell text={item.text} />}
                keyExtractor={(item) => item.id}
            />
        </View>
    )
}

另外,建议给FlatList添加keyExtractor,使用数据项的唯一标识作为key,避免使用默认的index引发性能和渲染异常问题。


内容的提问来源于stack exchange,提问作者sak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 05:47:07