React中如何计算筛选后表格列的总价?
React 筛选表格计算筛选后总价问题
我在React中实现了一个带筛选功能的简易表格,表格仅包含汽车的name和price字段,通过下拉选择框按汽车名称进行筛选。我需要展示筛选后汽车的总价,但尝试通过操作DOM计算总价的函数返回无效值。
尝试的函数代码:
const updateSubTotal = () => { var table = document.getElementById("myTable"); let subTotal = Array.from(table.rows) .slice(1) .reduce((total, row) => { return total + parseFloat(row.cells[1].innerHTML); }, 0); setTot(subTotal); };
完整代码:
import { useState } from "react"; import "./styles.css"; const data = [ { name: "Saab", price: 100 }, { name: "Mercedes", price: 50 }, { name: "Audi", price: 10 } ]; export default function App() { const [tot, setTot] = useState(); const updateSubTotal = () => { var table = document.getElementById("myTable"); let subTotal = Array.from(table.rows) .slice(1) .reduce((total, row) => { return total + parseFloat(row.cells[1].innerHTML); }, 0); setTot(subTotal); }; //CALCULATE sum of prices const totalPrice = data.map((item) => item.price).reduce((a, b) => a + b, 0); const [searchValue, setSearchValue] = useState(""); const DisplayData = data ?.filter((row) => row?.name?.match(new RegExp(searchValue, "i"))) .map((cars) => { return ( <tr key={cars.name}> <td>{cars?.name}</td> <td>{cars?.price}</td> </tr> ); }); return ( <div className="App"> <label for="cars">Choose a car:</label> <select name="cars" id="cars" value={searchValue} onChange={(e) => { setSearchValue(e.target.value); updateSubTotal(); }} > <option value="saab">Saab</option> <option value="mercedes">Mercedes</option> <option value="audi">Audi</option> </select> <table className="tables" id="myTable"> <thead className="sticky-header overflow-hidden z-50"> <tr> <th className="">Car Name</th> <th className="">Price</th> </tr> </thead> <tbody>{DisplayData}</tbody> </table> <div>Total Price without filter: {totalPrice}</div> <div>Total Price after filter: {tot}</div> </div> ); }
问题原因及解决方案
问题出在React状态更新的异步性:调用setSearchValue后,组件不会立即重新渲染,此时DOM还没更新为筛选后的内容,updateSubTotal操作DOM拿到的还是旧数据,导致计算结果错误。在React中应避免直接操作DOM获取数据,而是基于状态和原始数据计算结果。
修改后代码:
import { useState } from "react"; import "./styles.css"; const data = [ { name: "Saab", price: 100 }, { name: "Mercedes", price: 50 }, { name: "Audi", price: 10 } ]; export default function App() { const [searchValue, setSearchValue] = useState(""); // 先获取筛选后的数据集合 const filteredData = data?.filter((row) => row?.name?.match(new RegExp(searchValue, "i")) ); // 基于筛选后的数据计算总价 const filteredTotal = filteredData.reduce((total, item) => total + item.price, 0); // 计算全部汽车总价 const totalPrice = data.reduce((a, b) => a + b.price, 0); const DisplayData = filteredData.map((cars) => { return ( <tr key={cars.name}> <td>{cars?.name}</td> <td>{cars?.price}</td> </tr> ); }); return ( <div className="App"> <label htmlFor="cars">Choose a car:</label> <select name="cars" id="cars" value={searchValue} onChange={(e) => setSearchValue(e.target.value)} > <option value="saab">Saab</option> <option value="mercedes">Mercedes</option> <option value="audi">Audi</option> </select> <table className="tables" id="myTable"> <thead className="sticky-header overflow-hidden z-50"> <tr> <th>Car Name</th> <th>Price</th> </tr> </thead> <tbody>{DisplayData}</tbody> </table> <div>Total Price without filter: {totalPrice}</div> <div>Total Price after filter: {filteredTotal}</div> </div> ); }
关键修改点:
- 提取
filteredData变量,复用筛选后的数据,既用于渲染表格,也用于计算总价 - 通过
filteredData.reduce直接计算总价,完全避免操作DOM,结果准确且符合React状态驱动的理念 - 移除冗余的
tot状态和updateSubTotal函数,简化代码逻辑 - 修正
label的for属性为React规范的htmlFor,避免JSX关键字冲突
内容的提问来源于stack exchange,提问作者Teshie Ethiopia
相关产品推荐
相关产品推荐

