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

React UI无法展示后端API返回数据的问题排查与解决

问题排查与解决:React UI无法展示API返回的数据

问题背景

开发的React应用通过POST请求调用后端API处理图片,后端返回预期JSON数据,但UI无法展示提取结果,控制台无报错信息。

React组件代码

import React, { useState } from "react";
import axios from "axios";
import { useDropzone } from "react-dropzone";

interface ExtractedData {
  company: string;
  invoice_date: string;
  items: { description: string; quantity: number; amount: string }[];  // Changed amount to string for "$745.00" format
  total_amount: string;
  practitioner: string;
  patient: string;
  location: string;
  currency: string | null;
  other_details?: string;
}

const ImageUploadOCR: React.FC = () => {
  const [image, setImage] = useState<File | null>(null);
  const [data, setData] = useState<ExtractedData | null>(null);
  const [loading, setLoading] = useState<boolean>(false);

  const { getRootProps, getInputProps } = useDropzone({
    accept: { "image/*": [] },
    onDrop: (acceptedFiles) => setImage(acceptedFiles[0]),
  });

  const handleUpload = async () => {
    if (!image) return;

    setLoading(true);
    const formData = new FormData();
    formData.append("image", image);

    try {
      console.log("Data disk reached");
      const response = await axios.post("http://localhost:5000/api/extract", formData, {
        headers: { "Content-Type": "multipart/form-data" },
      });

      // Log the full response to verify the structure
      console.log("Response data:", response.data);

      // Set data to the state
      setData(response.data);

      // Optionally log company and invoice_date for debugging
      console.log("Company:", response.data?.company);
      console.log("Invoice Date:", response.data?.invoice_date);
    } catch (error) {
      console.error("Error uploading image:", error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="p-6 max-w-2xl mx-auto">
      <div {...getRootProps()} className="border-2 border-dashed p-4 cursor-pointer text-center">
        <input {...getInputProps()} />
        {image ? <p><img src={URL.createObjectURL(image)} /></p> : <p>Drag & drop an image, or click to select</p>}
      </div>
      <button className="mt-4 bg-blue-500 text-white px-4 py-2 rounded" onClick={handleUpload} disabled={!image || loading}>
        {loading ? "Processing..." : "Upload & Extract"}
      </button>

      {data && (
        <div className="mt-6">
          <h2 className="text-xl font-bold mb-2">Extracted Data</h2>
          <table className="w-full border-collapse border border-gray-300">
            <thead>
              <tr>
                <th className="border p-2">Field</th>
                <th className="border p-2">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td className="border p-2">Company</td>
                <td className="border p-2">{data?.company || "Not available"}</td> {/* Optional chaining added */}
              </tr>
              <tr>
                <td className="border p-2">Invoice Date</td>
                <td className="border p-2">{data?.invoice_date || "Not available"}</td> {/* Optional chaining added */}
              </tr>
            </tbody>
          </table>

          <h3 className="text-lg font-bold mt-4">Items</h3>
          <table className="w-full border-collapse border border-gray-300">
            <thead>
              <tr>
                <th className="border p-2">Description</th>
                <th className="border p-2">Quantity</th>
                <th className="border p-2">Amount</th>
              </tr>
            </thead>
            <tbody>
              {data.items.map((item, index) => (
                <tr key={index}>
                  <td className="border p-2">{item.description}</td>
                  <td className="border p-2">{item.quantity}</td>
                  <td className="border p-2">{item.amount}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
};

export default ImageUploadOCR;

后端返回的JSON数据

{
  "Currency": null,
  "Location": "102 Trope Street, New York, NY 45568",
  "Other relevant details": {
    "Due date": "07/30/23",
    "Invoice number": "12245",
    "Note": "A prescription has been written out for patient, for an acute throat infection.",
    "Subtotal": "$745.00",
    "Tax amount": "$157.05",
    "Tax rate": "9%"
  },
  "Patient": "Kemba Harris",
  "Practitioner": "Dr. Alanah Gomez",
  "Total Amount": "$1,902.05",
  "company": "Not specified",
  "invoice_date": "07/01/23",
  "items": [
    {
      "Amount": "$745.00",
      "Description": "Full Check Up",
      "Quantity": "1"
    },
    {
      "Amount": "$1,000.00",
      "Description": "Ear & Throat Examination",
      "Quantity": "1"
    }
  ]
}

问题原因

核心问题是后端返回的字段名、结构与前端TypeScript接口定义不匹配,导致React组件无法正确读取数据:

  1. 字段大小写不匹配:
    • 后端返回Location、Patient、Practitioner、Currency,但前端接口定义的是location、patient、practitioner、currency
    • 后端返回Total Amount,前端接口是total_amount;后端Other relevant details对应前端other_details
  2. items数组字段不匹配:
    • 后端items里的字段是Amount、Description、Quantity,但前端接口里是amount、description、quantity
  3. 类型不匹配:
    • 前端把quantity定义为number类型,但后端返回的是字符串格式(如"1")

解决方法

推荐在前端处理API响应时,做字段映射与类型转换,避免修改后端接口。修改handleUpload函数中的数据处理逻辑:

// 替换原setData(response.data)的代码
const mappedData: ExtractedData = {
  company: response.data.company || "Not available",
  invoice_date: response.data.invoice_date || "Not available",
  total_amount: response.data["Total Amount"] || "Not available",
  practitioner: response.data.Practitioner || "Not available",
  patient: response.data.Patient || "Not available",
  location: response.data.Location || "Not available",
  currency: response.data.Currency,
  other_details: JSON.stringify(response.data["Other relevant details"]) || undefined,
  items: response.data.items.map(item => ({
    description: item.Description || "",
    quantity: parseInt(item.Quantity) || 0, // 转换为number类型
    amount: item.Amount || ""
  }))
};

setData(mappedData);

同时,为了让UI展示更多字段,可以更新渲染部分的表格,添加缺失的字段:

// 在Extracted Data表格的tbody中添加以下行
<tr>
  <td className="border p-2">Practitioner</td>
  <td className="border p-2">{data?.practitioner || "Not available"}</td>
</tr>
<tr>
  <td className="border p-2">Patient</td>
  <td className="border p-2">{data?.patient || "Not available"}</td>
</tr>
<tr>
  <td className="border p-2">Location</td>
  <td className="border p-2">{data?.location || "Not available"}</td>
</tr>
<tr>
  <td className="border p-2">Total Amount</td>
  <td className="border p-2">{data?.total_amount || "Not available"}</td>
</tr>
<tr>
  <td className="border p-2">Other Details</td>
  <td className="border p-2">{data?.other_details || "Not available"}</td>
</tr>

验证

修改后,重新上传图片,控制台打印的mappedData会完全匹配前端接口定义,UI就能正确展示所有提取的数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:10:54