如何在反应中限制经常重新渲染的组件

Posted

技术标签:

【中文标题】如何在反应中限制经常重新渲染的组件【英文标题】:How to throttle often re-rendered component in react 【发布时间】:2021-11-28 08:32:27 【问题描述】:

我想限制连接到 WS 并经常获取数据的渲染组件,这会导致它经常重新渲染。 我有useMemo 钩子的解决方案,但我不确定useMemo 是为此类事情设计的。 当然,data 的每次更新都会导致重新渲染,因为useState 就是这样工作的,我必须更新这个data 状态。 您是否有一些建议或想法如何限制<DataVisualizator /> 组件的重新渲染?

useInterval hook

import  useEffect, useRef  from "react";

export const useInterval = (callback: () => void, delay: number) => 
  const savedCallback = useRef<() => void>();

  useEffect(() => 
    savedCallback.current = callback;
  , [callback]);

  useEffect(() => 
    function tick() 
      if (savedCallback.current) 
        savedCallback.current();
      
    
    if (delay !== null) 
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    
  , [delay]);
;

以及接收数据并应限制其子级的组件

import  useEffect, useMemo, useState  from "react";
import useWebSocket from "react-use-websocket";
import  useInterval  from "../Hooks";

export const WebSockets = () => 
  const SOCKET_URL = "wss://someWS";
  //data will be kind of Dictionary .eg  "key1": val, "anotherkey: valOther 
  const [data, setData] = useState();

  const webSocketOptions = 
    shouldReconnect: () => true,
    retryOnError: true,
    reconnectInterval: 3000,
    reconnectAttempts: 5,
    onError: (e) => console.log(e),
  ;

  const  sendMessage, lastMessage  = useWebSocket(
    SOCKET_URL,
    webSocketOptions
  );

  const handleData = (message: RequestData, data: OrderBookData) => 
    // lot of operations to deepClone state and set new with new Data
    setData(clonedData);
  ;
  useEffect(() => 
    lastMessage && handleData(JSON.parse(lastMessage.data), data);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  , [lastMessage]);

  const [tickThrottle, setTickThrottle] = useState(false);
  useInterval(() => 
    setTickThrottle(!tickThrottle);
  , 700);

  //Throttling with useMemo hook
  const throttledDataVisdsualizator = useMemo(
    () => <DataVisualizator dataToVisualize=data />,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [tickThrottle]
  );
  return (
    <>
        throttledDataVisdsualizator
    </>
  );
;

【问题讨论】:

【参考方案1】:

useMemo钩子解决

  const [tickThrottle, setTickThrottle] = useState(false);
  useInterval(() => 
    setTickThrottle(!tickThrottle);
  , 700);

  //Throttling with useMemo hook
  const throttledDataVisdsualizator = useMemo(
    () => <DataVisualizator dataToVisualize=data />,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [tickThrottle]
  );
  return (
    <>
        throttledDataVisdsualizator
    </>
  );

【讨论】:

这只会在data 始终是一个新对象的情况下进行限制;如果data 被内部修改,这些更改将被渲染。 @AKX 是的,数据将始终是新对象,在handleData 内部我对当前状态进行深度克隆并将修改后的深度克隆设置为新对象,因此数据始终是新对象

以上是关于如何在反应中限制经常重新渲染的组件的主要内容,如果未能解决你的问题,请参考以下文章

如何避免在反应功能组件中对“静态组件”进行不必要的重新渲染?

如何重新渲染 React 组件?

属性更改时如何重新渲染反应组件

如何从无限重新渲染中停止反应组件

避免在反应组件中无限重新渲染

如何修复反应过多的重新渲染错误?