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

React打字测试组件仅接收首次输入后停止运行的问题排查

问题排查结果

你的代码存在4处逻辑错误,直接导致组件只能响应首次按键:

  • React的setState是异步批量更新的,你在keyDown回调里调用changeInput(e.key)后,立刻传入compareCharacters的input还是上一次渲染的旧值,首次触发时input是初始空字符串,根本拿不到刚按下的键值
  • 直接对state存储的数组调用splice属于直接修改原状态,React无法检测到这种可变数据的变更,不会触发正常重渲染;而且Array.splice返回值是被删除元素组成的数组,不是删除首元素后的剩余数组,第一次执行后lorem状态会变成仅包含第一个被删除字符的数组,长度为1,后续自然无法匹配更多内容
  • 你同时维护了position位置索引、每次截断数组两套匹配定位逻辑,二者重复很容易出现索引越界、匹配错位的问题
  • 错误状态触发后没有重置逻辑,一旦输入错误就会永久保持错误样式
修复后代码

把重复的状态逻辑删掉,对比时直接使用事件对象返回的按键值,状态更新遵循不可变数据原则,修复后的代码如下:

import { useState } from "react"

const Input = ({text}) => {
    // 原始字符数组不需要每次修改,仅用position指针标记当前待匹配位置即可
    const [charList] = useState(text.split(''))
    const [position, setPosition] = useState(0)
    const [isError, setIsError] = useState(false)

    const handleKeyDown = (e) => {
        const pressedKey = e.key
        // 过滤Shift、Ctrl、退格等功能键,可根据自己的需求调整过滤规则
        if (pressedKey.length !== 1) return
        
        if (pressedKey === charList[position]) {
            // 用函数式更新保证拿到最新的position值,避免连续按键时状态计算错误
            setPosition(prev => prev + 1)
            setIsError(false)
        } else {
            setIsError(true)
        }
    }

  return (
    <input 
        className={`text ${isError ? 'new' : ''}`}
        type="text" 
        size="10000"
        onKeyDown={handleKeyDown}
        autoFocus
    />
  )
}

export default Input
额外注意点
  • 如果需要展示用户已输入的内容,可以单独维护一个输入值状态,但字符匹配逻辑不要依赖刚更新的state,直接取事件回调里拿到的e.key即可,避免React闭包陷阱拿到旧值
  • 所有基于原有state计算新state的场景,优先使用函数式更新写法,避免事件快速触发时状态更新不同步的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 13:18:20