所以这有点复杂。
我有一个 React 组件,客户询问我们是否可以将页面的一部分全屏显示(例如 YouTube 全屏视频)。我在组件的一角有一个小按钮,用户可以使用它来全屏切换组件的这一部分。
我遇到的问题是组件需要从另一个源提取的数据,并通过 React 内容对象传入。在页面加载之前需要这些数据。
所以我认为为此制作一个自定义钩子是有意义的。
我的钩子是这样的。
useFullScreen.tsx
import * as React from "react";
type useFullScreenProps = {
ref: React.MutableRefObject<null | HTMLDivElement>;
};
const useFullScreen = ({ref} : useFullScreenProps) => {
const [isFullScreen, setIsFullScreen] = React.useState(false);
const enterFullScreen = () => {
if (ref.current) {
ref.current.requestFullscreen();
}
};
const exitFullScreen = () => {
if (document.fullscreenElement) {
document.exitFullscreen();
}
};
const toggleFullScreen = () => {
isFullScreen ? exitFullScreen() : enterFullScreen();
};
React.useEffect(() => {
const handleFullscreenChange = () => {
setIsFullScreen(document.fullscreenElement !== null);
};
document.addEventListener("fullscreenchange", handleFullscreenChange);
return () => document.removeEventListener("fullscreenchange", handleFullscreenChange);
}, []);
return [isFullScreen, toggleFullScreen];
};
export default useFullScreen;
查看器组件这样调用它。
ViewerComponent.tsx
import useFullScreen from "./Common/useFullScreen";
const ViewerComponent = () => {
let viewerRef = React.useRef<HTMLDivElement>(null);
const [isFullScreen, toggleFullScreen] = useFullScreen(viewerRef as any);
const viewData = useClientObject<ExamData>(React.useContext(ClientContext), "viewer_data");
if (viewData === undefined || Object.keys(viewData).length === 0) {
return <h4> Loading page</h4>
}
return (
<div id="view-workspace" ref={viewerRef}>
<button onClick={toggleFullScreen as () => void}>
{isFullScreen ? 'Exit Fullscreen' : 'Enter Fullscreen'}
</button>
<div> {/* Rest of the page goes here */} </div>
<div>
)
};
所以问题是我不知道如何将 ref 传递给 hook 以便它可以使用它。
因为我的页面在渲染整个组件之前使用了它所需的数据。它永远看不到
viewerRef
DOM 元素。
我已经尝试了所有方法,使用useEffect我可以正确获取对dom元素的引用,但是我不知道如何再次调用该钩子?
React.useEffect(()=>{
console.log(viewerRef.current) <-- this works, but now how do I tell the hook about it
},
[examData])
建议: 传递给
{ ref: viewerRef }
时使用useFullScreen
作为参数。
这是修改后的代码:
const [isFullScreen, toggleFullScreen] = useFullScreen({ ref: viewerRef });
这里的主要变化是无论数据是否已完成加载,都将
div
指向的 viewerRef
(即 <div id="view-workspace" ref={viewerRef}>
)保留在 DOM 中。这样,即使在初始渲染期间尚未加载数据,viewerRef.current
仍然可以指向这个div
元素。
不建议先将
viewerRef
转换为 any
,然后再将其传递给 useFullScreen
。
强制转换为
any
会削弱类型检查,可能会导致传递错误参数时无法及时检测到错误。
例如,如果
useFullScreen
需要一个对象作为参数,但使用 any
绕过类型检查,TypeScript 将不会抛出错误。
如果以后
useFullScreen
需要更多的参数,这种直接传递的方式也不容易扩展。