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

React Native中如何处理WebSocket高频数据流以避免界面冻结?

高效处理React Native中WebSocket高频实时数据的方案

核心优化思路

因为数据仅需展示无需持久化,核心是避免全局状态更新引发的全组件重渲染,改用局部状态+组件拆分+非状态变量结合的方式,同时优化WebSocket的连接管理。

具体优化步骤

1. 用useRef替代useState存储实时数据

useRef的更新不会触发组件重渲染,适合存储仅用于展示的高频数据:

// 替换原来的useState
const marketDataRef = useRef({});

2. 拆分独立展示组件并使用memo包装

将每个标的的展示拆分为独立组件,用React.memo包裹,只有当props变化时才重渲染:

// 新建单个标的展示组件
import React, { memo } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';

const TickerItem = memo(({ label, value }) => (
  <View style={{flexDirection:'column'}}>
    <Text style={{fontSize:25, color:'#4c80cf', fontWeight:'500',textAlign:'center'}}>{label}</Text>
    <TouchableOpacity>
      <Text style={{fontSize:30, fontWeight:'800',alignSelf:'center'}}>{value}</Text>
    </TouchableOpacity>
  </View>
));

export default TickerItem;

3. 优化WebSocket连接与数据更新逻辑

  • 将WebSocket实例移到useEffect内部,避免组件重复创建连接
  • 直接更新useRef的值,并用forceUpdate触发局部组件刷新(仅更新需要变化的部分)

修改后的HomeScreen核心代码:

import { View, Text, SafeAreaView, Dimensions, TouchableOpacity } from 'react-native'
import React, { useEffect, useRef, useState } from 'react'
import { ScrollView } from 'react-native-gesture-handler'
import Strikes from './Strikes';
import TickerItem from './TickerItem';

const width = Dimensions.get('window').width
const height = Dimensions.get('window').height

export default function HomeScreen() {
  const marketDataRef = useRef({});
  const wsRef = useRef(null);
  const [, forceUpdate] = useState({}); // 用于局部触发更新
  const requestArray = ["nse_cm_nifty_50","nse_cm_nifty_bank","nse_fno_banknifty_05012023_43000_ce","nse_fno_banknifty_05012023_43000_pe","nse_fno_banknifty_05012023_43100_ce","nse_fno_banknifty_05012023_43100_pe","nse_fno_banknifty_05012023_43200_ce","nse_fno_banknifty_05012023_43200_pe","nse_fno_banknifty_05012023_43300_ce","nse_fno_banknifty_05012023_43300_pe","nse_fno_banknifty_05012023_43400_ce","nse_fno_banknifty_05012023_43400_pe","nse_fno_banknifty_05012023_43500_ce","nse_fno_banknifty_05012023_43500_pe"]

  useEffect(() => {
    const url = "WebsocketURL";
    wsRef.current = new WebSocket(url);
    
    const ws = wsRef.current;
    ws.onopen = () => {
      const requestString = requestArray.join(',');
      ws.send(`type=msubscribe&${requestString}&columns=20`);
    };

    ws.onmessage = async (e) => {
      const res = await new Response(e.data).text();
      const responsedata = res.split('\n');
      const updatedData = {...marketDataRef.current};
      
      for (let i=0; i<responsedata.length-2; i++) {
        const tempdata = responsedata[i].split('|');
        updatedData[tempdata[0]] = tempdata[1];
      }
      
      marketDataRef.current = updatedData;
      forceUpdate({}); // 触发组件更新,仅memo后的子组件会按需重渲染
    };

    ws.onerror = (e) => {
      console.log(e.message);
    };

    ws.onclose = (e) => {
      console.log(e.code, e.reason);
    };

    // 组件卸载时关闭连接
    return () => {
      ws.close();
    };
  }, []);

  return (
    <SafeAreaView style={{flex:1 ,backgroundColor:'#ebecee',shadowColor:'black',borderBottomStartRadius:10,borderBottomEndRadius:10}}>
      <View>
        <View style={{padding:20}}>
          <Text style={{fontSize:30,fontWeight:'bold'}}>Marketwatch</Text>
        </View>
        <View style={{flexDirection:'row',marginTop:5,justifyContent:'space-around'}}>
          <TickerItem label="NIFTY 50" value={marketDataRef.current.nse_cm_nifty_50} />
          <TickerItem label="BANK NIFTY" value={marketDataRef.current.nse_cm_nifty_bank} />
        </View>
        <View style={{width:width-20,borderRadius:5,backgroundColor:'#810a0a',height:60,justifyContent:'space-around',alignItems:'center',alignSelf:'center',marginTop:10,marginBottom:5,flexDirection:'row'}}>
          <Text style={{color:'white',fontSize:25,fontWeight:'400'}}>Expiry </Text>
          <Text style={{color:'white',fontSize:25,fontWeight:'400'}}>5-DEC-2023</Text>
        </View>
      </View>
      <ScrollView style={{flex:1 ,backgroundColor:'white',width:width,marginTop:5,height:height}} showsVerticalScrollIndicator={false}>
        <View style={{flex:1, padding:20,flexDirection:'row',alignItems:'center',justifyContent:'space-between',marginTop:5,marginBottom:0}}>
          <Text style={{color:'green',fontSize:15,fontWeight:'800'}}>CALLS</Text>
          <Text style={{color:'black',fontSize:20,fontWeight:'800',textDecorationLine:'underline'}}>STRIKE</Text>
          <Text style={{color:'red',fontSize:15,fontWeight:'800'}}>PUTS </Text>
        </View>
        <View style={{ borderBottomColor: '#ebecee', borderBottomWidth:2,}}/>
        <Strikes strike={43000} ce={marketDataRef.current.nse_fno_banknifty_05012023_43000_ce} pe={marketDataRef.current.nse_fno_banknifty_05012023_43000_pe}/>
        <Strikes strike={43100} ce={marketDataRef.current.nse_fno_banknifty_05012023_43100_ce} pe={marketDataRef.current.nse_fno_banknifty_05012023_43100_pe}/>
        <Strikes strike={43200} ce={marketDataRef.current.nse_fno_banknifty_05012023_43200_ce} pe={marketDataRef.current.nse_fno_banknifty_05012023_43200_pe}/>
        <Strikes strike={43300} ce={marketDataRef.current.nse_fno_banknifty_05012023_43300_ce} pe={marketDataRef.current.nse_fno_banknifty_05012023_43300_pe}/>
        <Strikes strike={43400} ce={marketDataRef.current.nse_fno_banknifty_05012023_43400_ce} pe={marketDataRef.current.nse_fno_banknifty_05012023_43400_pe}/>
        <Strikes strike={43500} ce={marketDataRef.current.nse_fno_banknifty_05012023_43500_ce} pe={marketDataRef.current.nse_fno_banknifty_05012023_43500_pe}/>
      </ScrollView>
    </SafeAreaView>
  )
}

4. 给Strikes组件添加memo包装

确保Strikes组件只有当props变化时才重渲染:

// 修改Strikes组件
import React, { memo } from 'react';
// ... 原有代码

const Strikes = memo(({ strike, ce, pe }) => {
  // ... 原有渲染逻辑
});

export default Strikes;

额外优化建议

  • 数据防抖:如果更新频率过高(比如每秒几十次),可以添加防抖逻辑,控制UI更新频率,避免过度渲染:
    import { debounce } from 'lodash';
    
    const updateUI = debounce(() => {
      forceUpdate({});
    }, 50); // 每50ms更新一次UI
    
    // 在onmessage中调用updateUI替代直接forceUpdate
    marketDataRef.current = updatedData;
    updateUI();
    
  • WebSocket连接复用:如果多个页面需要WebSocket连接,考虑将连接逻辑封装到自定义Hook中,避免重复创建连接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:11:04