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
相关产品推荐
相关产品推荐

