React点击表格行获取行列数据并传递给其他组件的实现方法
问题修复方案
你当前代码的核心问题有3个:
- 非表单元素(td)不存在
value属性,你在onClick里取e.target.value永远拿到空值;用innerHTML取值会把单元格里嵌套的<p>标签等冗余内容一起带进来,数据不准 - 除了team1Back之外,其余的team1Lay、drawBack、drawLay、team2Back、team2Lay要么没绑定点击赋值逻辑,要么取值方式错误
- 点击赔率单元格后没有同步触发PlaceBett组件的显示开关,数据存完也不会自动弹出组件
修复步骤
- 不要从DOM节点取数:表格渲染用的所有数据本来就在传入的
dataprops里,点击的时候直接拿对应下标的数据赋值即可,完全不需要依赖event对象取DOM内容,从根源避免取值错误。 - 统一给所有可点击的赔率/数值单元格绑定点击事件,点击时一次性把对应行的BACK、LAY值存入对应state,同时触发PlaceBett组件显示。
- 修正state更新方法的命名(原代码里
SetDrawLay/SetDrawBack首字母大写不符合React Hook的命名规范,统一改成小驼峰setDrawLay/setDrawBack)。
修复后的核心代码
import { useState } from "react"; import PlaceBett from "./PlaceBett"; const MatchBetTable = ({ data }) => { const [showPlaceBet, setShowPlaceBet] = useState(false); const [team1Back, setTeam1Back] = useState(""); const [team1Lay, setTeam1Lay] = useState(""); const [team2Lay, setTeam2Lay] = useState(""); const [team2Back, setTeam2Back] = useState(""); // 修正set方法命名 const [drawLay, setDrawLay] = useState(""); const [drawBack, setDrawBack] = useState(""); // 统一处理赔率点击,直接从传入的data取数,不依赖DOM const handleOddsClick = (rowType) => { // rowType 对应 1=主队 2=平局 3=客队 const rowData = data.values[rowType - 1]; switch(rowType) { case 1: setTeam1Back(rowData.odds ?? "-"); setTeam1Lay(rowData.val2 ?? 0); break; case 2: setDrawBack(rowData.odds ?? "-"); setDrawLay(rowData.val2 ?? 0); break; case 3: setTeam2Back(rowData.odds ?? "-"); setTeam2Lay(rowData.val2 ?? 0); break; default: break; } // 赋值后打开投注组件 setShowPlaceBet(true); }; return ( <> {showPlaceBet && ( <PlaceBett data={data} team1Back={team1Back} team1Lay={team1Lay} team2Back={team2Back} team2Lay={team2Lay} drawBack={drawBack} drawLay={drawLay} onClose={() => setShowPlaceBet(false)} /> )} <table className="table-auto mb-4 text-black w-full "> <thead className="bg-gray-500 md:p-5 p-1 text-sm"> <tr> <th className="md:p-5 p-1 text-sm">{data.name}</th> <th className="md:p-5 p-1 text-sm" colSpan="5"></th> <th className="md:p-5 p-1 text-sm">BET DELAY-3 SEC</th> </tr> </thead> <thead> <tr className="bg-white md:p-5 p-1 text-sm border border-table_border"> <th className="md:p-5 p-1 text-sm">MAX 50000</th> <th className="md:p-5 p-1 text-sm" colSpan="2"></th> <th className="md:p-5 p-1 text-sm bg-table_row-blue border border-table_border "> BACK <p>(Back)</p> </th> <th className="md:p-5 p-1 text-sm text-black bg-table_row-cream border border-table_border"> LAY <p>(lay)</p> </th> <th className="md:p-5 p-1 text-sm" colSpan="2"></th> </tr> </thead> <tbody> {/* 主队行 */} <tr className="md:p-5 p-1 text-sm border border-table_border text-center"> <td className="bg-gray-300 md:p-5 p-1 text-sm"> {data.values[0].val1 === null ? "-" : data.values[0].val1} </td> <td className="md:p-5 p-1 text-sm bg-table_row-blue border border-table_border"> -<p>(-)</p> </td> <td className="md:p-5 p-1 text-sm bg-table_row-blue border border-table_border "> -<p>(-)</p> </td> <td className="md:p-5 p-1 text-sm bg-table_row-blue border border-table_border cursor-pointer hover:opacity-80" onClick={() => handleOddsClick(1)} > {data.values[0].odds === null ? "-" : data.values[0].odds} </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border cursor-pointer hover:opacity-80" onClick={() => handleOddsClick(1)} > {data.values[0].val2 === null ? 0 : data.values[0]?.val2} </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border "> -<p>(-)</p> </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border "> -<p>(-)</p> </td> </tr> {/* 平局行 */} {data.values[1] && ( <tr className="md:p-5 p-1 text-sm border border-table_border text-center"> <td className="bg-gray-300 md:p-5 p-1 text-sm"> {data.values[1]?.val1} </td> <td className="md:p-5 p-1 text-sm bg-table_row-blue border border-table_border "> -<p>(-)</p> </td> <td className="md:p-5 p-1 text-sm bg-table_row-blue border border-table_border "> -<p>(-)</p> </td> <td className="md:p-5 p-1 odd:bg-table_row-cream text-sm bg-table_row-blue border border-table_border cursor-pointer hover:opacity-80" onClick={() => handleOddsClick(2)} > {data.values[1]?.odds} </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border cursor-pointer hover:opacity-80" onClick={() => handleOddsClick(2)} > {data.values[1]?.val2 === null ? "0" : data.values[1]?.val2} </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border"> -<p>(-)</p> </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border"> -<p>(-)</p> </td> </tr> )} {/* 客队行 */} {data?.values[2] && ( <tr className="md:p-5 p-1 text-sm border border-table_border text-center"> <td className="bg-gray-300 md:p-5 p-1 text-sm"> {data?.values[2] && data.values[2]?.val1} </td> <td className="md:p-5 p-1 text-sm bg-table_row-blue border border-table_border "> -<p>(-)</p> </td> <td className="md:p-5 p-1 text-sm bg-table_row-blue border border-table_border "> -<p>(-)</p> </td> <td className="md:p-5 p-1 odd:bg-table_row-cream text-sm bg-table_row-blue border border-table_border cursor-pointer hover:opacity-80" onClick={() => handleOddsClick(3)} > {data?.values[2] && data.values[2]?.odds} </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border cursor-pointer hover:opacity-80" onClick={() => handleOddsClick(3)} > {data.values[2]?.val2 === null ? "0" : data.values[2]?.val2} </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border"> -<p>(-)</p> </td> <td className="md:p-5 p-1 text-sm bg-table_row-cream border border-table_border"> -<p>(-)</p> </td> </tr> )} </tbody> </table> </> ); }; export default MatchBetTable;
额外说明
- 给可点击的单元格加了
cursor-pointer和hover透明度变化的样式,用户能明确感知这是可点击区域 - 给PlaceBett组件传入了
onClose回调,方便组件内部加关闭按钮控制弹窗隐藏 - 空值统一用
??空值合并运算符处理,逻辑和你原来的判断一致,写法更简洁 - 不要在调用
setXxx之后立刻打印对应state的值,React的state更新是批量异步的,立刻拿不到最新值,要观察值变化可以用useEffect依赖对应state打印。
内容的提问来源于stack exchange,提问作者Vikash kumar
相关产品推荐
相关产品推荐

