React 中自定义钩子的威力(响应式设计示例)

2025-05-25

React 中自定义钩子的威力(响应式设计示例)

一般来说,自定义钩子是一种很好的模式,可以处理应用程序中的模块化和组合性。您几乎可以为所有内容编写自定义钩子!

顺便说一句,如果您对自定义钩子感兴趣,我假设您熟悉 React 钩子概念。如果不熟悉,不用担心,您可以在这里阅读相关内容。

这里值得一提的是(摘自 React 文档):

Hooks 是一种函数,它允许你从函数组件中“钩住” React 的状态和生命周期功能。Hooks 不能在类内部使用——它们允许你在没有类的情况下使用 React。(我们不建议你一夜之间重写现有组件,但如果你愿意,可以在新组件中使用 Hooks。)

“虎克船长”

让我们以响应式窗口处理为例。

响应式设计最常见的方法是CSS 媒体查询,但在某些情况下,我们希望通过JavaScript来处理它(有条件地渲染组件、在窗口大小改变到某个点时执行某些逻辑等)。

在下面的示例中,您将看到如何使用React hooks来实现该目的 + 编写代码并在应用程序中重用/共享它。

一些声明

我们的自定义钩子被调用并作为可选对象useResponsiveWindow获取。sizes

钩子名称约定是一个前缀use后跟一个故事叙述,驼峰命名的名称(如useState,,,等)useRefuseContext

大多数应用程序都使用这些常见的尺寸,这些尺寸使用声明为默认尺寸DEFAULT_SIZES,但您可以随意更改或将自己的尺寸传递给钩子。

DESKTOP_MIN尺寸也是桌面视图的标准最小分辨率(再次强调,这不是禁忌......)。我们稍后会使用它。

首先,我们要在加载时保存宽度和高度的状态useState

const DEFAULT_SIZES = {
  small: [1366, 768],
  medium: [1400, 900],
  large: [1920, 1080],
  mobile: [360, 640]
};

export enum ResolutionState {
  XS = "Extra Small",
  SMALL = "Small",
  MEDIUM = "Medium",
  LARGE = "Large"
}

const DESKTOP_MIN = [1280, 720];

const useResponsiveWindow = (sizes = DEFAULT_SIZES) => {
  const [width, setWidth] = useState(window.innerWidth);
  const [height, setHeight] = useState(window.innerHeight);
  const resizeTimer = useRef(null);

.........
Enter fullscreen mode Exit fullscreen mode

跟踪窗口大小并存储它

添加调整大小事件监听器(卸载时将其删除)并执行,handleWindowResize这将保存新值。

.....

  const handleWindowResize = useCallback((e) => {
    clearTimeout(resizeTimer.current);
    resizeTimer.current = setTimeout(() => {
      setWidth(e.target.innerWidth);
      setHeight(e.target.innerHeight);

    }, 200);

  }, [setWidth, setHeight, resizeTimer]);

  useEffect(() => {
    window.addEventListener('resize',handleWindowResize);
    return () => {
      window.removeEventListener('resize', handleWindowResize);
    };
  }, [handleWindowResize]);

.....
Enter fullscreen mode Exit fullscreen mode

有用的见解

现在我们有了宽度、高度和分辨率阈值,我们得到了一些可以在应用程序中使用的见解。

.....

  const resolutionState = useCallback((type) => {
    const index = type === 'width' ? 0 : 1;
    const value = type === 'width' ? width : height;
    if(value >= sizes?.small[index] && value < sizes?.medium[index]) {
      return ResolutionState.SMALL;
    } else if(value >= sizes?.medium[index] && value < sizes?.large[index]) {
      return ResolutionState.MEDIUM;
    } else if(value >= sizes?.large[index]) {
      return ResolutionState.LARGE;
    } else {
      return ResolutionState.XS;
    }
  }, [width, height]);

  const widthState = resolutionState('width');
  const heightState = resolutionState('height');

  const isMobile = useMemo(() => sizes?.mobile && width <= sizes?.mobile[0] && height <= sizes?.mobile[1], [width, height]);

  const isDesktop = useMemo(() => width >= DESKTOP_MIN[0] && height >= DESKTOP_MIN[1], [width, height]);

.....
Enter fullscreen mode Exit fullscreen mode

消耗钩子

const SomeComponent= () => {
  const {
    width,
    height,
    isMobile,
    isDesktop,
    widthState,
    heightState
  } = useResponsiveWindow();

  useEffect(() => {
    console.log(`Width state now is: ${widthState}`);
    // do something here...
  }, [widthState]);

  return (
    <div>
      <p>{`${width} (${widthState}) x ${height} (${heightState})`}</p>
      {isMobile && <div>Mobile View</div>}
      {isDesktop && <div>Desktop View</div>}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

您可以在此处查看示例并在此处查看源代码:

结论

有许多库提供了许多自定义钩子作为解决方案,并且您的应用程序可能有很多这样的钩子,但是尝试找到一些您可以自己实现的钩子,它将:

  • 节省您的捆绑包大小。
  • 让您完全控制您的代码。
  • 将您的代码技能扩展到应用程序边界之外,进入基础设施区域。

关于这个钩子 - 它并不完美,并且可能能够根据您的需要提供更多的见解和有用的数据。

非常欢迎提出建议和想法:)

该图片由Dean MoriartyPixabay上发布

文章来源:https://dev.to/mlevi1806/the-power-of-custom-hooks-in-react-responsive-design-example-4flb
PREV
破解面试密码的7个有效步骤
NEXT
您不知道自己需要的 API