React中如何更新对象数组 实现交易对数据无重复展示
问题根源
当前代码出现重复Pair条目的核心原因有三个:
- 组件内部游离定义的
DATA数组在每次组件重渲染时都会被重置为空数组,回调逻辑未做存在性判断,收到推送就全量push新条目 - WebSocket订阅逻辑未做生命周期管控,组件每次重渲染都会重复创建订阅,多份回调同时触发会重复写入数据
- 回调更新状态时直接操作临时数组,没有基于已有的行情状态做匹配更新,旧条目不会被替换只会追加新条目
实现方案
废弃独立的DATA临时数组,所有行情数据统一存在TickerFeed状态中;收到WebSocket推送时,以Pair字段为唯一标识做增量更新:已存在的Pair直接替换价格、成交量等字段,不存在的Pair新增到列表中;同时将订阅逻辑放到useEffect中,组件挂载时仅订阅一次,卸载时取消订阅避免内存泄漏。
为了提升匹配效率,更新时先将已有状态转为Pair为键的Map结构,避免每次遍历数组查找,更新完成后再转回数组存入状态。
修复后完整代码
import { useState, useEffect } from 'react'; import { View, StyleSheet } from 'react-native'; // 按项目实际路径导入DataTable相关组件 // import { DataTable } from 'xxx'; function App() { const [TickerFeed, SetTickerFeed] = useState([]); useEffect(() => { // 组件挂载时初始化一次订阅 const subscription = orionUnit.priceFeed.ws.subscribe("allTickers", { callback: (tickers) => { let keys = zodUtil.util.objectKeys(tickers); let values = zodUtil.util.objectValues(tickers); SetTickerFeed(prevFeed => { // 把已有数据转成以Pair为键的Map,查找复杂度O(1) const tickerMap = new Map(prevFeed.map(item => [item.Pair, item])); for (let i = 0; i < keys.length; i++) { const currentPair = keys[i]; // 已存在的Pair覆盖最新数据,不存在的自动新增 tickerMap.set(currentPair, { Pair: currentPair, LastPrice: values[i].lastPrice, Volume: values[i].volume, OpenPrice: values[i].openPrice, LowPrice: values[i].lowPrice, HighPrice: values[i].highPrice }) } // 转回数组更新状态 return Array.from(tickerMap.values()); }) } }); // 组件卸载时取消订阅,避免内存泄漏和重复回调 return () => { // 若SDK取消订阅方法名不是unsubscribe,替换成对应方法即可 subscription.unsubscribe?.(); } }, []); // 空依赖数组,保证仅在组件挂载时执行一次订阅逻辑 return ( <View style={styles.container}> <DataTable> <DataTable.Header> <DataTable.Title>Pair</DataTable.Title> <DataTable.Title>LastPrice</DataTable.Title> <DataTable.Title>Volume</DataTable.Title> <DataTable.Title>OpenPrice</DataTable.Title> <DataTable.Title>LowPrice</DataTable.Title> <DataTable.Title>HighPrice</DataTable.Title> </DataTable.Header> {TickerFeed.map((item) => ( <DataTable.Row key={item.Pair}> <DataTable.Cell>{item.Pair}</DataTable.Cell> <DataTable.Cell numeric>{item.LastPrice}</DataTable.Cell> <DataTable.Cell numeric>{item.Volume}</DataTable.Cell> <DataTable.Cell numeric>{item.OpenPrice}</DataTable.Cell> <DataTable.Cell numeric>{item.LowPrice}</DataTable.Cell> <DataTable.Cell numeric>{item.HighPrice}</DataTable.Cell> </DataTable.Row> ))} </DataTable> </View> ); } export default App;
逻辑说明
- 首次收到全量tickers推送时,Map为空,所有Pair会作为新条目写入,完成初始化加载
- 后续收到WebSocket推送时,已存在的Pair会直接覆盖最新的行情字段,不会新增重复条目
- 若推送中出现之前不存在的新Pair,会自动追加到列表中,不需要额外处理
- 使用函数式状态更新
SetTickerFeed(prevFeed => {})可以保证每次更新拿到的都是最新的行情列表,避免闭包导致的旧状态问题
内容的提问来源于stack exchange,提问作者GarlicBread
相关产品推荐
相关产品推荐

