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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 19:06:04