React 中自定义钩子的威力(响应式设计示例)
一般来说,自定义钩子是一种很好的模式,可以处理应用程序中的模块化和组合性。您几乎可以为所有内容编写自定义钩子!
顺便说一句,如果您对自定义钩子感兴趣,我假设您熟悉 React 钩子概念。如果不熟悉,不用担心,您可以在这里阅读相关内容。
这里值得一提的是(摘自 React 文档):
Hooks 是一种函数,它允许你从函数组件中“钩住” React 的状态和生命周期功能。Hooks 不能在类内部使用——它们允许你在没有类的情况下使用 React。(我们不建议你一夜之间重写现有组件,但如果你愿意,可以在新组件中使用 Hooks。)

让我们以响应式窗口处理为例。
响应式设计最常见的方法是CSS 媒体查询,但在某些情况下,我们希望通过JavaScript来处理它(有条件地渲染组件、在窗口大小改变到某个点时执行某些逻辑等)。
在下面的示例中,您将看到如何使用React hooks来实现该目的 + 编写代码并在应用程序中重用/共享它。
一些声明
我们的自定义钩子被调用并作为可选对象useResponsiveWindow
获取。sizes
钩子名称约定是一个前缀,
use
后跟一个故事叙述,驼峰命名的名称(如useState
,,,等)useRef
useContext
大多数应用程序都使用这些常见的尺寸,这些尺寸使用声明为默认尺寸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);
.........
跟踪窗口大小并存储它
添加调整大小事件监听器(卸载时将其删除)并执行,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]);
.....
有用的见解
现在我们有了宽度、高度和分辨率阈值,我们得到了一些可以在应用程序中使用的见解。
.....
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]);
.....
消耗钩子
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>
);
};
您可以在此处查看示例并在此处查看源代码:
结论
有许多库提供了许多自定义钩子作为解决方案,并且您的应用程序可能有很多这样的钩子,但是尝试找到一些您可以自己实现的钩子,它将:
- 节省您的捆绑包大小。
- 让您完全控制您的代码。
- 将您的代码技能扩展到应用程序边界之外,进入基础设施区域。
关于这个钩子 - 它并不完美,并且可能能够根据您的需要提供更多的见解和有用的数据。
非常欢迎提出建议和想法:)
文章来源:https://dev.to/mlevi1806/the-power-of-custom-hooks-in-react-responsive-design-example-4flb