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

React+Redux受控输入中检测输入耗时,区分扫码与手动输入

解决React+Redux环境下条码输入耗时检测的问题

我明白你遇到的问题了——因为组件render会频繁触发,直接在render里用new Date()没法持续追踪计时状态。我们可以把计时相关的状态存在组件的实例变量或者组件内部state里(这部分属于组件UI逻辑,不需要放到Redux里),这样就能在输入过程中持续维护计时信息了。

下面是修改后的完整代码,我会标注关键改动:

import React from "react";
import StoreInput from "../StoreInput/index";
import { connect } from "react-redux";
import "./index.scss";
import { setStoreInputFieldValue } from "../../actions/store.actions";
import { addArticleToStore } from "../../actions/articles.actions";

type ScanSetProps = {
  // Redux State
  storeInputFieldValue?: any;
  // Redux Actions
  setStoreInputFieldValue?: any;
  addArticleToStore?: any;
};

class ScanSet extends React.Component<ScanSetProps> {
  // 定义实例变量存储开始计时的时间,组件生命周期内会持续保留
  startTime: number | null = null;

  handleScanSet = (event) => {
    const { setStoreInputFieldValue, storeInputFieldValue } = this.props;
    const newValue = event.target.value;
    
    // 1. 处理计时逻辑:从空输入变为非空时,记录开始时间
    if (!storeInputFieldValue && newValue) {
      this.startTime = Date.now();
    }

    // 2. 当输入清空时,重置计时
    if (!newValue) {
      this.startTime = null;
    }

    // 3. 当输入长度达到13位时,计算耗时并判断输入方式
    if (newValue.length === 13 && this.startTime) {
      const elapsedTime = Date.now() - this.startTime;
      const isScanner = elapsedTime <= 150; // 留一点容错空间,100-150ms都算扫描
      console.log(isScanner ? "条码扫描器输入" : "手动输入");
      
      // 这里可以根据判断结果执行后续逻辑,比如自动触发添加操作
      if (isScanner) {
        this.props.addArticleToStore(newValue);
        // 扫描完成后清空输入并重置计时
        setStoreInputFieldValue("");
        this.startTime = null;
      }
    }

    // 更新Redux中的输入值
    setStoreInputFieldValue(newValue);
  };

  // Component render
  render() {
    const { storeInputFieldValue, addArticleToStore } = this.props;
    return (
      <div className="ScanSet">
        <StoreInput
          idStoreInput={"scanSetInput"}
          typeStoreInput={"number"}
          placeholderStoreInput={
            "Scannez le code barre ou saisissez le code EAN"
          }
          storeInputFillMethod={this.handleScanSet}
        />
        <button
          id="scanSetButton"
          className={
            storeInputFieldValue?.length === 13
              ? "enabledButton"
              : "disabledButton"
          }
          onClick={() => addArticleToStore(storeInputFieldValue)}
          disabled={storeInputFieldValue?.length !== 13}
        >
          Ajouter
        </button>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  storeInputFieldValue: state.store.storeInputFieldValue,
});

const mapDispatchToProps = (dispatch) => ({
  setStoreInputFieldValue: (input_value) => dispatch(setStoreInputFieldValue(input_value)),
  addArticleToStore: (article_ean) => dispatch(addArticleToStore(article_ean)),
});

export default connect(mapStateToProps, mapDispatchToProps)(ScanSet);

关键逻辑说明:

  • 实例变量startTime:用来存储输入开始的时间戳,它属于组件实例,不会随render重新创建,能在输入过程中持续保留状态。
  • 计时触发条件:当输入从空变为非空时(!storeInputFieldValue && newValue),记录当前时间;如果输入被清空,重置startTime。
  • 耗时计算与判断:当输入长度达到13位时,计算当前时间与startTime的差值,这里把阈值设为150ms(比100ms多一点容错,因为不同扫描器速度略有差异),判断是否为扫描输入。
  • 扫描自动处理:如果判定是扫描器输入,可以自动触发addArticleToStore并清空输入,提升用户体验;手动输入则保持原有按钮触发逻辑。

另外,我还给按钮加了disabled属性,确保只有输入长度为13时才能点击,比单纯靠className更严谨。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 07:27:35