如何根据设备大小使用组件?



如何根据设备的大小显示不同的html元素或组件?在react中,可以使用一个名为react-responsive的包。但是在Next中,在我使用这个包的每个组件中,ssr都不会在该组件上运行。你通常是怎么做的?毕竟,很多时候,比如Windows上显示的东西和手机上应该显示的东西差别很大,应该使用其他的html代码。

由于NextJs是服务器端渲染的,因此服务器无法知道它将生成的html发送到什么屏幕大小

现在'useEffect'来拯救,因为useEffect将只在客户端运行。

我们可以使用它来获取页面加载到浏览器后的屏幕大小类型。

你可以按以下方式使用'react-device-detect'。

import { isMobile } from 'react-device-detect';
// declare a state
const [stateMobile, setState] = useState(false);
useEffect(() => {
if (!isMobile && typeof window !== 'undefined') {
setState(stateMobile);
} else {
setState(!stateMobile);
}
}, []);

然后在你的返回

return (
<>
{isMobile ? (
<div> Mobile html here </div> 
) : (
<div> Desktop html here </div>
)}
</>
);

在你的app.js文件中使用这个方法一次,并将它作为props传递给layout。而不是在每个组件中使用useeffect。

好的,所以如果我已经理解了你的问题,你试图呈现一个页面与所有设备相关的组件,但显示(与css)只有当前设备的组件。

我的方法是:

在你的页面组件:

// imports
const PageComponent = () => {
const resizeTimoutRef = useRef(null)
const [screenSizeState, setScreenSizeState] = useState(null) // initialized at null because on the server you don't have the DOM
// basic function to get the breakpoint as a string based on the width of the window
const getScreenSize = windowWidth =>
windowWidth < 768
? "sm"
windowWidth < 1024
? "md"
: windowWidth < 1280
? "lg"
: "xl"
useEffect(() => {
// here i set the current screen breakpoint immediately on the page load
setScreenSizeState(getScreenSize(window.innerWidth))
// here i add a listener for the resize event of the window
window.addEventListener('resize', () => {
// if a resize timout exists i clear it to prevent calling setState too many times
if(resizeTimeoutRef.current) clearTimeout(resizeTimeoutRef.current)
// here i set the timeout ref to the function that will be executed 150ms after the last resize event, again, to prevent calling setState too many times
resizeTimeoutRef.current = setTimeout(() => setScreenSizeState(getScreenSize(window.innerWidth)), 150)
})
}, []) // empty array means that this hook will be called only once on the first page load
return (
<>
<div style={{ display: screenSizeState === 'sm' ? 'block' : 'none' }}>
Always present in the DOM but displayed only on 'sm' breakpoint
</div>
<div style={{ display: ['md', 'lg'].includes(screenSizeState) ? 'block' : 'none' }}>
Always present in the DOM but displayed only on 'md' and 'lg' breakpoints
</div>
</>
)
}
export default PageComponent

说,当然,你可以把这段代码改编成一个自定义钩子,使其可重用,只需这样做:

// hooks/useScreenSize.js
// imports
export const useScreenSize = () => {
const resizeTimoutRef = useRef(null)
const [screenSizeState, setScreenSizeState] = useState(null)
const getScreenSize = windowWidth =>
windowWidth < 768
? "sm"
windowWidth < 1024
? "md"
: windowWidth < 1280
? "lg"
: "xl"
useEffect(() => {
setScreenSizeState(getScreenSize(window.innerWidth))
window.addEventListener('resize', () => {
if(resizeTimeoutRef.current) clearTimeout(resizeTimeoutRef.current)
resizeTimeoutRef.current = setTimeout(() => setScreenSizeState(getScreenSize(window.innerWidth)), 150)
})
}, [])
return screenSizeState
}

这样你就可以在你的页面组件中使用它,像这样:

// pages/index.jsx
// imports
const PageComponent = () => {
const breakpointState = useScreenSize()
return (
<>
<div style={{ display: breakpointState === 'sm' ? 'block' : 'none' }}>
Always present in the DOM but displayed only on 'sm' breakpoint
</div>
<div style={{ display: ['md', 'lg'].includes(breakpointState) ? 'block' : 'none' }}>
Always present in the DOM but displayed only on 'md' and 'lg' breakpoints
</div>
</>
) 
}
export default PageComponent

最新更新