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

React中onChange事件获取输入值少一位的问题及解决方法

React onChange获取输入值丢失最后一个字符的解决办法

你的问题核心是React的useState更新是异步的:在输入框的onChange事件中,你先调用setTotalVal(event.target.value),紧接着就执行calcAvg(),此时totalVal还没完成更新,calcAvg里拿到的仍是更新前的旧值,所以总是少最后一个输入的字符。

下面是具体的修复方案:

1. 直接传递最新输入值给计算函数

不用依赖state里的totalVal,而是把输入框的实时值作为参数传给calcAvg,确保拿到完整的内容:

// 修改onChange事件逻辑
onChange={(event) => {
  const newValue = event.target.value;
  setTotalVal(newValue);
  calcAvg(newValue); // 直接传递最新输入值
}}

// 同步修改calcAvg函数
const calcAvg = (currentTotalVal = totalVal) => {
  // 先处理空值、非法输入的边界情况,避免报错
  if (!currentTotalVal.trim() || !shares.trim() || isNaN(shares)) {
    setAvgText("");
    return;
  }
  try {
    const sum = eval(currentTotalVal);
    if (isNaN(sum)) throw new Error("无效数值");
    const avg = sum / parseFloat(shares);
    setAvgText(`: ₹${avg.toFixed(2)}`);
  } catch (error) {
    setAvgText(": 输入格式错误,请检查");
  }
};

2. 用state管理计算结果,避免直接操作DOM

React不推荐直接通过document.getElementById修改DOM,新增一个state来控制平均价格的显示:

// 新增state存储计算结果文本
const [avgText, setAvgText] = useState("");

然后在JSX中直接渲染这个state:

<div
  className="p-2 my-8 unselectable cursor-pointer flex w-full justify-center bg-green-400 hover:bg-green-500 text-white font-medium rounded"
  onClick={calcAvg}>
  Average Price {avgText}
</div>

3. 修复Enter键添加+的异步问题

handleKeyDown中直接使用totalVal也可能拿到旧值,改用函数式更新确保获取最新的state:

const handleKeyDown = (event) => {
  if (event.key === 'Enter') {
    setTotalVal(prev => prev + "+"); // 函数式更新,拿到最新的prev值
  }
};

完整修复后的代码

import React, {useState} from "react";

function Average() {
    const [totalVal, setTotalVal] = useState("");
    const [shares, setShares] = useState("");
    const [avgText, setAvgText] = useState("");

    const handleKeyDown = (event) => {
      if (event.key === 'Enter') {
        setTotalVal(prev => prev + "+");
      }
    };

    // 自定义求和函数替代eval,避免安全风险
    const calculateSum = (str) => {
      return str.split('+').reduce((sum, num) => {
        const parsed = parseFloat(num.trim());
        return isNaN(parsed) ? sum : sum + parsed;
      }, 0);
    };

    const calcAvg = (currentTotalVal = totalVal) => {
      if (!currentTotalVal.trim() || !shares.trim() || isNaN(shares)) {
        setAvgText("");
        return;
      }
      try {
        const sum = calculateSum(currentTotalVal);
        const avg = sum / parseFloat(shares);
        setAvgText(`: ₹${avg.toFixed(2)}`);
      } catch (error) {
        setAvgText(": 输入格式错误,请检查");
      }
    };
    
  return (
    <>
      <div>
          <div className="my-4">
            <label className="block">
              <input
                type="number"
                id="totalShares"
                className="mt-1 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-500 focus:outline-none focus:border-slate-300 focus:ring-slate-300 block w-full rounded-md sm:text-sm focus:ring-1"
                placeholder="Enter number of stocks"
                value={shares}
                onChange={(event) => setShares(event.target.value)}
              />
            </label>
          </div>
    
          <div className="my-4">
            <label className="block">
              <input
                type="text"
                id="stockVal"
                value={totalVal}
                className="mt-1 px-3 py-2 bg-white border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-slate-300 focus:ring-slate-300 block w-full rounded-md sm:text-sm focus:ring-1"
                placeholder="Enter price of every stock with + in between"
                autoComplete="off"
                onChange={(event) => {
                  const newValue = event.target.value;
                  setTotalVal(newValue);
                  calcAvg(newValue);
                }}
                onKeyDown={handleKeyDown}
              />
            </label>
          </div>

          <div
            className="p-2 my-8 unselectable cursor-pointer flex w-full justify-center bg-green-400 hover:bg-green-500 text-white font-medium rounded"
            onClick={calcAvg}>
            Average Price {avgText}
          </div>
      </div>
    </>
  );
}

export default Average;

额外提示

  • 代码中用自定义的calculateSum替代了eval,避免eval带来的安全风险(恶意输入可能执行危险代码),同时更可控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:45:15