通过创建新事件,计算活动断点从 O(n) 减少到 O(1)。有什么缺点吗?

问题描述 投票:0回答:1

我有一个 Next.js 14 项目,在该项目中,我尽可能优先使用服务器组件而不是客户端组件。

布局是服务器渲染的,而其中使用的组件包装器是客户端渲染的。这些组件之一在页面上多次实例化,其内部工作的一部分涉及初始化

useBreakpoint
钩子的实例。

useBreakpoint
钩子的目的是根据屏幕尺寸计算并返回当前断点状态(两个字母的字符串)。

当我们在应用程序中有此钩子的多个实例时,每个实例都会在每个调整大小事件上计算当前断点。这导致时间复杂度为 O(n),其中 n 是初始化钩子的组件数量。

由于主要布局是服务器渲染的,因此像 React Context 或 Redux 这样的单例解决方案将无法工作。

这就是为什么我想出了以下内容:

import { useEffect, useState } from 'react'; import { BreakpointKey, getBreakpointKey } from '@/lib/breakpoints'; const handleResize = () => { const width = window.innerWidth; const matchingBreakpoint = getBreakpointKey(width); const event = new CustomEvent('breakpointChange', { detail: matchingBreakpoint }); window.dispatchEvent(event); }; const useBreakpoint = () => { const [breakpoint, setBreakpoint] = useState<BreakpointKey>('zr'); useEffect(() => { const handleBreakpointChange = (event: CustomEvent<BreakpointKey>) => { setBreakpoint(event.detail); }; window.addEventListener('breakpointChange', handleBreakpointChange); window.addEventListener('resize', handleResize); return () => { window.removeEventListener('breakpointChange', handleBreakpointChange); }; }, []); return breakpoint; }; export default useBreakpoint;
所以基本上,我们附加了一个调整大小事件处理程序的实例,其唯一目的是触发一个自定义的 

breakpointChange

 事件,该事件保存计算断点的有效负载。因此,钩子的所有实例现在都可以注册自己的 
breakpointChange
 事件侦听器,而无需每个实例都执行相同的计算。因此,从计算断点的 O(n) 开始,该解决方案将其减少到 O(1)。

我在简短的研究中没有遇到过这种方法,所以我想在这里分享它以征求您的反馈。有什么我可能忽略的缺点吗?例如,是否值得为此目的创建一个全新的活动?谢谢!

reactjs next.js react-hooks dom-events react-server-components
1个回答
0
投票
不清楚您认为在这里优化的到底是什么。根据我对代码的理解和看到,您仍然有

N 组件调用 useBreakpoint 钩子,该钩子实例化了 "resize"

 侦听器 
"breakpointChange"
 事件侦听器,所以 
N useBreakpoint
 挂钩调用最终会触发 
N handleResize
handleBreakpointChange
 调用。如果与仅在 
O(c * n) 事件处理程序中完成工作相比,这已经创建了 更多 工作(
尽管数量恒定,因此根据您的计算,
c * O(n)
"resize"
)。此外,
useBreakpoint
钩子忽略清理
"resize"
侦听器。

建议重构

删除
    "breakpointChange"
  • 事件调度和侦听器,它所做的只是将
    "resize"
    事件映射到
    "breakpointChange"
    事件。
    正确维护事件监听器,包括在组件卸载时删除它们。
  • handleResize
  • 处理程序
     移至 
    useEffect 钩子回调主体,这样它就不是外部依赖项。
    import { useEffect, useState } from 'react';
    import { BreakpointKey, getBreakpointKey } from '@/lib/breakpoints';
    
    const useBreakpoint = () => {
      const [breakpoint, setBreakpoint] = useState<BreakpointKey>('zr');
    
      useEffect(() => {
        const handleResize = () => {
          const width = window.innerWidth;
          const matchingBreakpoint = getBreakpointKey(width);
          setBreakpoint(matchingBreakpoint);
          // or setBreakpoint(getBreakpointKey(window.innerWidth));
        };
    
        window.addEventListener('resize', handleResize);
    
        // Invoke once to set state for initial window width
        handleResize();
        
        return () => {
          window.removeEventListener('resize', handleResize);
        };
      }, []);
    
      return breakpoint;
    };
    
    export default useBreakpoint;
    

© www.soinside.com 2019 - 2024. All rights reserved.