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

React中如何为特定输入框显示错误提示?

问题背景

我有一个存储产品信息的 state:

const [rowsData, setRowsData] = useState([
    { width: "", height: "", quantity: "" },
]);

还有一个支持按需添加/删除行的表格:

return (
    <> 
      {rowsData.map((data, index) => {
        const { width, height, quantity} = data;
        return (
          <tr key={index}>
            <td>{index + 1}</td>
            <td>
              <input
                type="number"
                value={width}
                onChange={(evnt) => handleChange(index, evnt)}
                name="width"
                className={wError ? "input input-error border-2 input-bordered w-full max-w-xs" : "input input-bordered w-full max-w-xs"}            
              />
            </td>
            <td>
              <input
                type="number"
                value={height}
                onChange={(evnt) => handleChange(index, evnt)}
                name="height"
                className={hError ? "input input-error border-2 input-bordered w-full max-w-xs" : "input input-bordered w-full max-w-xs"}
              />{" "}
            </td>
            <td>
              <input
                type="number"
                value={quantity}
                onChange={(evnt) => handleChange(index, evnt)}
                name="quantity"
                className={qError ? "input input-error border-2 input-bordered w-full max-w-xs" : "input input-bordered w-full max-w-xs"}
              />{" "}
            </td>
            <td>
              {index !==0 ? <button className="btn" onClick={() => deleteTableRows(index)}>
                x
              </button>: null}
            </td>
          </tr>
        );
      })}

处理输入变化的 handleChange 函数:

const handleChange = (index, evnt) => {
    const { name, value } = evnt.target;
    const rowsInput = [...rowsData];
    rowsInput[index][name] = value;
    setRowsData(rowsInput);
};

需求:提交时所有字段必须仅接受数字,若输入非数字,对应输入框需显示红色错误边框。

我尝试的解决方案:

  1. 为每个字段创建单独的错误 state:
const [wError, setWError] = useState(false);
const [hError, setHError] = useState(false);
const [qError, setQError] = useState(false);
  1. 检查每个输入框的值是否为数字:
const createOrder = () => {
    let wCheck, hCheck, qCheck

    rowsData.map((e) => {
       wCheck = !isNaN(e.width) && !isNaN(parseFloat(e.width));
       hCheck = !isNaN(e.height) && !isNaN(parseFloat(e.height));
       qCheck = !isNaN(e.quantity) && !isNaN(parseFloat(e.quantity));
    });
};
  1. 设置错误状态:
setWError(!wCheck);
setHError(!hCheck);
setQError(!qCheck);
  1. 根据错误状态为输入框添加样式(如上述表格代码所示)

问题
这个方案存在严重 bug:错误状态仅由最后一行的输入决定,导致整列要么全标红,要么全显示正常,无法定位到具体某一行的单个输入框。请问如何修改才能让错误提示精准对应到单个输入框?


修复方案

核心问题是你用了三个全局错误变量,无法区分不同行的错误。正确的做法是维护一个与 rowsData 结构完全对应的错误状态数组,让错误信息和每行数据绑定。

步骤1:初始化对应结构的错误 state

将错误状态改成数组,每个元素对应一行的三个字段错误情况:

const [rowErrors, setRowErrors] = useState([
  { width: false, height: false, quantity: false }
]);

步骤2:完善提交验证逻辑

在 createOrder 中逐行逐字段验证,生成对应的错误数组:

const createOrder = () => {
  // 生成和rowsData匹配的错误数组
  const newErrors = rowsData.map(row => ({
    width: isNaN(row.width) || isNaN(parseFloat(row.width)),
    height: isNaN(row.height) || isNaN(parseFloat(row.height)),
    quantity: isNaN(row.quantity) || isNaN(parseFloat(row.quantity))
  }));
  setRowErrors(newErrors);

  // 检查是否存在错误,无错误时执行提交逻辑
  const hasError = newErrors.some(err => err.width || err.height || err.quantity);
  if (!hasError) {
    // 这里编写提交订单的业务逻辑
    console.log("提交数据:", rowsData);
  }
};

步骤3:修改表格输入框的样式绑定

让每个输入框的错误样式对应当前行的字段错误状态:

{rowsData.map((data, index) => {
  const { width, height, quantity} = data;
  const currentRowErrors = rowErrors[index]; // 获取当前行的错误信息
  return (
    <tr key={index}>
      <td>{index + 1}</td>
      <td>
        <input
          type="number"
          value={width}
          onChange={(evnt) => handleChange(index, evnt)}
          name="width"
          className={currentRowErrors.width ? "input input-error border-2 input-bordered w-full max-w-xs" : "input input-bordered w-full max-w-xs"}            
        />
      </td>
      <td>
        <input
          type="number"
          value={height}
          onChange={(evnt) => handleChange(index, evnt)}
          name="height"
          className={currentRowErrors.height ? "input input-error border-2 input-bordered w-full max-w-xs" : "input input-bordered w-full max-w-xs"}
        />{" "}
      </td>
      <td>
        <input
          type="number"
          value={quantity}
          onChange={(evnt) => handleChange(index, evnt)}
          name="quantity"
          className={currentRowErrors.quantity ? "input input-error border-2 input-bordered w-full max-w-xs" : "input input-bordered w-full max-w-xs"}
        />{" "}
      </td>
      <td>
        {index !==0 ? <button className="btn" onClick={() => deleteTableRows(index)}>
          x
        </button>: null}
      </td>
    </tr>
  );
})}

步骤4:同步维护添加/删除行的错误状态

确保添加或删除行时,错误数组和数据数组同步更新:

// 添加行函数示例
const addTableRow = () => {
  setRowsData(prev => [...prev, { width: "", height: "", quantity: "" }]);
  setRowErrors(prev => [...prev, { width: false, height: false, quantity: false }]);
};

// 删除行函数示例
const deleteTableRows = (index) => {
  setRowsData(prev => prev.filter((_, i) => i !== index));
  setRowErrors(prev => prev.filter((_, i) => i !== index));
};

可选优化:实时验证

如果想在用户输入时就实时提示错误,可以修改 handleChange 函数:

const handleChange = (index, evnt) => {
  const { name, value } = evnt.target;
  const rowsInput = [...rowsData];
  rowsInput[index][name] = value;
  setRowsData(rowsInput);

  // 实时验证当前修改的字段
  const newErrors = [...rowErrors];
  newErrors[index][name] = isNaN(value) || isNaN(parseFloat(value));
  setRowErrors(newErrors);
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 11:07:01