React Native:如何让已编写的checkVal函数按既定逻辑正常运行?
原代码核心运行错误
- Hooks使用违规:把
useState定义在普通函数checkVal内部,违反React Hooks仅能在组件顶层/自定义Hook中调用的规则,直接触发运行时崩溃 - 计数器逻辑完全失效:每次执行
checkVal都会重新初始化count为0,永远无法累计到2次的判断分支,超阈值次数统计完全失效 - 语法结构错误:多条件阈值判断的括号未闭合,分支判断顺序颠倒,代码逻辑根本无法按预期执行
- Modal渲染逻辑错误:直接在函数内嵌入
<Teken_1_Modal />、<Dial />的JSX代码,无法触发组件正常渲染,必须通过受控state控制Modal的显隐属性 - 状态关联缺失:超阈值尝试次数没有按单个参数维度存储,
item、inputValue、阈值上下限min/max等变量未从组件遍历上下文关联,存在大量未定义引用 - CheckBox交互不符合要求:未实现“勾选后禁用”的逻辑,无法满足勾选后不可取消的业务规则
可落地实现方案
核心状态定义(完全匹配业务逻辑要求)
需要在组件顶层定义以下受控状态,不能放到普通校验函数内部:
- 按参数维度存储的超阈值尝试次数:用对象结构存储,key为
requestId + 参数编码,value为0-2的数字,实现每个参数独立计数 - 两个Modal的显隐控制状态:
teken1ModalVisible、teken2ModalVisible - CheckBox的控制状态:是否显示、是否选中、是否禁用
- 当前触发校验的参数项、输入值的临时存储状态,方便传值给弹窗组件
重构后可运行完整代码
import { useState } from 'react'; import CheckBox from '@react-native-community/checkbox'; import { Teken_1_Modal } from '../components/Teken_1_Modal'; import { Teken_2_Modal } from '../components/Teken_2_Modal'; import { Dial } from '../components/Dial'; // 假设页面入参为参数列表、当前请求ID function ParamInputPage({ paramList, requestId }) { // 按参数维度存储超阈值尝试次数 const [thresholdViolationCount, setThresholdViolationCount] = useState({}); // 弹窗显隐控制 const [teken1ModalVisible, setTeken1ModalVisible] = useState(false); const [teken2ModalVisible, setTeken2ModalVisible] = useState(false); // CheckBox状态控制 const [showConfirmCheckBox, setShowConfirmCheckBox] = useState(false); const [isConfirmChecked, setIsConfirmChecked] = useState(false); const [checkBoxDisabled, setCheckBoxDisabled] = useState(false); // 临时存储当前触发校验的上下文 const [currentCheckedItem, setCurrentCheckedItem] = useState(null); const [currentInputValue, setCurrentInputValue] = useState(''); // 纯函数:判断输入值是否超出参数阈值 const isValueOutOfThreshold = (item, value) => { const inputNum = Number(value); if (isNaN(inputNum)) return false; const min = item.Immediate_Report_Min; const max = item.Immediate_Report_Max; if (min == null && max !== null) return inputNum > max; if (min !== null && max == null) return inputNum < min; if (min !== null && max !== null) return inputNum < min || inputNum > max; return false; }; // 核心校验函数 const checkVal = (item, inputValue) => { const paramKey = `${requestId}_${item.Parameter_Code}`; const currentCount = thresholdViolationCount[paramKey] || 0; // 达到2次尝试上限,直接拦截 if (currentCount >= 2) return; // 输入值合法场景处理 const isOutOfRange = isValueOutOfThreshold(item, inputValue); if (!isOutOfRange) { setThresholdViolationCount(prev => ({...prev, [paramKey]: 0})); setShowConfirmCheckBox(false); setIsConfirmChecked(false); setCheckBoxDisabled(false); return; } // 超阈值,累计尝试次数 const newCount = currentCount + 1; setThresholdViolationCount(prev => ({...prev, [paramKey]: newCount})); setCurrentCheckedItem(item); setCurrentInputValue(inputValue); // 第一次超阈值:弹出Teken1弹窗,显示CheckBox if (newCount === 1) { setTeken1ModalVisible(true); setShowConfirmCheckBox(true); return; } // 第二次超阈值:直接弹出Teken2弹窗 if (newCount === 2) { setTeken2ModalVisible(true); setIsConfirmChecked(true); setCheckBoxDisabled(true); return; } }; // CheckBox变更逻辑 const handleCheckBoxChange = (newValue) => { setIsConfirmChecked(newValue); if (newValue) { // 勾选后立刻禁用,不可取消 setCheckBoxDisabled(true); // 关闭Teken1弹窗,弹出Teken2弹窗 setTeken1ModalVisible(false); setTeken2ModalVisible(true); } }; return ( <View style={{padding: 16}}> {/* 遍历参数渲染输入框 */} {paramList.map((item, index) => { const currentInput = item.currentInputValue || ''; return ( <View key={item.Parameter_Code} style={{marginBottom: 20}}> <View style={styles.ParamViewInput}> <TextInput style={styles.ParamTextInput} blurOnSubmit={true} autoCapitalize="none" autoCorrect={false} keyboardType="number-pad" maxLength={6} placeholder="input.." onChangeText={(text) => { // 替换为你原有onChangeInput的更新逻辑 const updatedList = [...paramList]; updatedList[index].currentInputValue = text; }} value={currentInput} // 失焦/提交键盘完成时触发校验 onBlur={() => checkVal(item, currentInput)} onSubmitEditing={() => checkVal(item, currentInput)} /> <Text style={styles.label_C}>{item.Parameter_Units}</Text> <TouchableOpacity onPress={() => { // 替换为你原有历史弹窗的触发逻辑 }} style={styles.ParameterUnit}> <Text style={styles.Hlable}>H</Text> </TouchableOpacity> </View> {/* 仅第一次超阈值时显示CheckBox */} {showConfirmCheckBox && ( <CheckBox disabled={checkBoxDisabled} value={isConfirmChecked} onValueChange={handleCheckBoxChange} /> )} </View> ); })} {/* Teken1弹窗:第一次超阈值时弹出 */} <Teken_1_Modal visible={teken1ModalVisible} onClose={() => setTeken1ModalVisible(false)} currentItem={currentCheckedItem} inputValue={currentInputValue} /> {/* Teken2弹窗:第二次超阈值/用户勾选CheckBox时弹出 */} <Teken_2_Modal visible={teken2ModalVisible} onClose={() => { setTeken2ModalVisible(false); // 弹窗关闭后重置当前参数的违规次数 const paramKey = currentCheckedItem ? `${requestId}_${currentCheckedItem.Parameter_Code}` : ''; if (paramKey) { setThresholdViolationCount(prev => ({...prev, [paramKey]: 0})); } setShowConfirmCheckBox(false); setIsConfirmChecked(false); setCheckBoxDisabled(false); }} currentItem={currentCheckedItem} inputValue={currentInputValue} > {/* Dial组件作为Teken2弹窗的内容渲染 */} <Dial currentValue={currentInputValue} min={currentCheckedItem?.Immediate_Report_Min} max={currentCheckedItem?.Immediate_Report_Max} /> </Teken_2_Modal> </View> ); }
业务逻辑匹配校验
- 超阈值次数拦截:每个参数的尝试次数独立存储,达到2次上限后直接拦截后续超阈值输入,不会触发任何弹窗
- 首次超阈值交互:自动弹出Teken1_Modal,在输入框下方显示CheckBox;用户勾选CheckBox后立即禁用勾选框(不可取消),自动弹出Teken2_Modal并展示Dial组件
- 第二次超阈值交互:不弹出Teken1_Modal,直接弹出Teken2_Modal并展示Dial组件
- 合法输入自动重置:当用户输入值回到阈值范围内,自动重置该参数的违规计数,恢复初始交互状态
内容的提问来源于stack exchange,提问作者MariaJ
相关产品推荐
相关产品推荐

