# Landscape-full-screen (React Hook)
:::info
index.html (不重要,主要邏輯在下方 index.js)
```htmlmixed=
// 宣告一個 root 標籤
<div id="root"></div>
```
:::
#### useEffect
你可以先粗略理解為 render 結束後的 callback
#### useState
你可以先粗略理解為 class 底下的 property
:::success
index.js
```jsx=
import React, { useEffect, useState, useRef } from 'react';
// 渲染方法
import { render } from 'react-dom';
import './style.css';
const isPortrait = () => (window.innerWidth < window.innerHeight);
const App = () => {
// 設定 showSwipeUp(boolean) 預設值為 false
const [ showSwipeUp, setShowSwipeUp ] = useState(false);
// game-content 設定在 css,hide 設定在 css -> display: none
const gameContentClasses = showSwipeUp ? 'game-content hide' : 'game-content';
// swipe-up 設定在 css,show 設定在 css -> display: block
const swipeUpClasses = showSwipeUp ? 'swipe-up show' : 'swipe-up';
// 渲染完的 callback
useEffect(() => {
// 比較短的為高
const screenHeight = Math.min(window.screen.width, window.screen.height);
// 檢查 toolbar 是否顯示中
const onCheckSwipeUp = () => {
const show = screenHeight - window.innerHeight > 40;
// 設定 showSwipeUp = show
setShowSwipeUp(show);
}
// 100 毫秒檢查一次 toolbar 是否顯示中
setInterval(onCheckSwipeUp, 100);
// 下次 effect 執行前,清除 onCheckSwipeUp Interval,避免重複呼叫 Interval
return () => {
clearIntrerval(onCheckSwipeUp);
}
// 此參數決定 effect 調用時機
// 預設是每次渲染後都會執行
// [] 空陣列,表示只在此組件被載入時執行一次
}, []);
// 渲染完的 callback
useEffect(() => {
const onResize = () => {
// keep scroll to botoom at portrait mode.
// 當在 landscape 時須設定為 0, 才能讓 swipe up div 在正確位置出現
const offsetY = isPortrait() ? 9999 : 0;
window.requestAnimationFrame(() => {
window.scrollTo(0, offsetY);
});
}
onResize();
// 監聽視窗尺寸變動事件
window.addEventListener('resize', onResize);
// 下次 effect 執行前,清除 listener,避免重複監聽事件
return (() => {
window.removeEventListener('resize', resize);
});
// 此參數決定 effect 調用時機
// 預設是每次渲染後都會執行
// [] 空陣列,表示只在此組件被載入時執行一次
}, []);
// 渲染結構
return (
<div>
// 渲染 game-content(不重要)
<GameCanvas className={gameContentClasses}/>
// 渲染 swipe up 字樣
<div className={swipeUpClasses}>
<span>swipe up</span>
</div>
</div>
);
}
// 渲染 App 至 root 這個節點(root 被定義在 index.html)
render(<App />, document.getElementById('root'));
```
:::
:::info
GameCanvas.js
```jsx=
import React, { useEffect, useRef } from 'react';
const GameCanvas = ({ className }) => {
const canvasRef = useRef(null);
useEffect(() => {
const onResize = () => {
const canvas = canvasRef.current;
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr);
ctx.font = '48px serif';
ctx.fillText('Hello world', 10, 50);
}
onResize();
window.addEventListener('resize', onResize);
return (() => {
window.removeEventListener('resize', resize);
})
}, []);
return (
<canvas ref={canvasRef} className={className}></canvas>
)
}
export default GameCanvas;
```
:::
### 幫助理解 useState
```jsx=
import React, { useState } from 'react';
function Example() {
// 宣告一個新的 state 變數,我們稱作為「count」。
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
```
等價於
```javascript=
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
```
相關文章
[Tricky Solution](https://medium.com/@humanhighway/tips-about-how-to-make-a-landscape-fullscreen-webpage-in-ios-safari-2d6d0e94d324)
[React useState](https://zh-hant.reactjs.org/docs/hooks-state.html)
[React useEffect](https://zh-hant.reactjs.org/docs/hooks-effect.html)
[React useRef](https://zh-hant.reactjs.org/docs/hooks-reference.html)
[resize event](https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event)
###### tags: `Egret`