React函数结果无法渲染:表格报错与数据展示问题
问题分析与解决方案
核心错误原因
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'indexOf')
你错误地将Stock组件当作普通类用new Stock()实例化,但它本质是React组件,不能通过new创建实例。同时Stock返回的是异步函数的Promise对象,React尝试渲染这个Promise时触发了内部错误。表格不允许文本子节点
{loading && "Loading..."}直接将文本作为<table>的直接子元素,而HTML规范中<table>的直接子元素只能是<thead>、<tbody>、<tfoot>等,文本节点属于非法子元素。数据无法渲染到页面
你在map中用同步变量存储异步获取的数据,Promise完成后更新变量不会触发React重新渲染;同时map中的JSX没有return,导致根本不会生成表格行。
修复步骤
1. 重构Stock.js为工具函数
因为Stock不需要渲染UI,只是获取数据,所以改成纯异步工具函数:
import { FetchStockPrice, FetchStockDividend } from './StockData'; export const getStockData = async (stockTicker, shares) => { const price = await FetchStockPrice(stockTicker); const div = await FetchStockDividend(stockTicker); const divAmnt = (div * price).toFixed(2); const annual = divAmnt * shares; return { price: price.toFixed(2), divYield: div, divAmnt: divAmnt, annual: annual }; };
2. 修复ShowStock.js的渲染逻辑
- 将加载提示移到表格外,避免非法子节点
- 用状态存储所有股票的详细数据,批量异步获取
- 修正JSX语法错误,添加必要的
return和key属性
import { useState, useEffect } from 'react'; import { UserAuth } from './你的Auth路径'; // 补充实际路径 import { collection } from 'firebase/firestore'; // 补充导入 import { useCollectionData } from 'react-firebase-hooks/firestore'; // 补充导入 import { getStockData } from './Stock'; const ShowStock = () => { const { user } = UserAuth(); const [stockDetails, setStockDetails] = useState({}); const [isLoadingDetails, setIsLoadingDetails] = useState(false); const dir = `users/${user.uid}/invList`; const q = collection(db, dir); const [docs, loading, error] = useCollectionData(q); // 批量获取所有股票数据 useEffect(() => { if (!loading && docs) { setIsLoadingDetails(true); const fetchAllData = async () => { const detailsMap = {}; for (const stock of docs) { detailsMap[stock.stockTicker] = await getStockData(stock.stockTicker, 1); } setStockDetails(detailsMap); setIsLoadingDetails(false); }; fetchAllData(); } }, [docs, loading]); // 加载状态处理 if (loading || isLoadingDetails) { return <div>Loading...</div>; } // 错误处理 if (error) { return <div>Error: {error.message}</div>; } return ( <div> <table className="table table-striped"> <thead> <tr> <th scope="col">Stock Ticker</th> <th scope="col">Price</th> <th scope="col">Dividend Yeild %</th> <th scope="col">Dividend Amount Annually</th> <th scope="col">Annual Dividend Profits</th> </tr> </thead> <tbody> {docs?.map((stock) => { const details = stockDetails[stock.stockTicker]; if (!details) return null; return ( <tr key={stock.stockTicker}> <th>{stock.stockTicker}</th> <td>{details.price}</td> <td>{details.divYield}</td> <td>{details.divAmnt}</td> <td>{details.annual}</td> </tr> ); })} </tbody> </table> </div> ); }; export default ShowStock;
额外注意点
- React中要用
className替代class(class是JS关键字) - 遍历列表时必须添加
key属性,帮助React识别元素变化 - 原代码中
let divA =存在语法错误,已在重构中消除
内容的提问来源于stack exchange,提问作者Dotman
相关产品推荐
相关产品推荐

