# 面試 PLUS
讀書會時間
星期六 21:00
星期日 10:00
[面試題庫統計表(向小哥致敬)](https://docs.google.com/spreadsheets/d/1gQ6M8_1hQWx-YZVbiNZaRrS5n5dzIv9UEcbEjj2BPsw/edit#gid=0)
---
### 九月第一週 報告日 9/5(日) 10:00
收單時間:9/3(五) 22:00
##### (日)
#### `Promise.all()` 當中有 promise 被 reject 的運作機制 [東]
::: spoiler code 考題與觀念說明
What's the output?
```javascript=
const promise1 = Promise.resolve('First')
const promise2 = Promise.resolve('Second')
const promise3 = Promise.reject('Third')
const promise4 = Promise.resolve('Fourth')
const runPromises = async () => {
const res1 = await Promise.all([promise1, promise2])
const res2 = await Promise.all([promise3, promise4])
return [res1, res2]
}
runPromises()
.then(res => console.log(res))
.catch(err => console.log(err))
```
### 觀念
#### `Promise.resolve()`, `Promise.reject()`
- 兩者都是 static method
- **`Promise.resolve(value);`**
returns a Promise object that is resolved with a given value.
- **`Promise.reject(reason);`**
returns a Promise object that is rejected with a given reason.
<br >
#### `Promise.all()`
**`Promise.all(iterable);`**
- return **一個 Promise 物件**
- 這個 return 的 promise 物件在下列的情況會 fulfilled(resolved)
- 當 input 的 iterable of promises 中所有的 promises 都被resolved(fulfilled)
- 或 input 中的 iterable 不含任何 promise 時,被實現。
- 這個 return 的 promise 物件在下列的情況會 **立刻 rejected**
- 任何 input 中的 promise 被 rejects
- non-promises throwing an error
並且 reject with **this first rejection message / error**
!!! [注意]
根據 MDN,實務上不建議像第 9 行用一個 array 直接 return 兩個 Promise,而是會用 `Promise.all()` 或 `Promise.allSettled` 處理,這題的重點是上述概念
:::
#### `this` 綜合題
:::spoiler YPO 機上題
```javascript=
function getName() {
return this.name;
}
const name = 'A';
const obj = {
name: 'B',
getName: getName,
type: {
name: 'C',
getName() {
return this.name;
}
},
props: {
name: 'D',
getName: () => this.name,
}
}
const test = obj.getName;
// 1.
console.log(obj.getName());
// 2.
console.log(obj.type.getName());
// 3.
console.log(obj.props.getName());
// 4.
console.log(test());
```
<img src="https://i.imgur.com/I5yWDa6.png" width="350px">
<img src="https://i.imgur.com/jSwq7Ut.png" width="350px">
#### 3,4 題除了 array function 的 `this` 觀念以外的重點:
**`const` 宣告的 global variable 不會被加入 window 的 property (`let` 也是)**
:::
#### React code 改善情境題
:::spoiler YPO 機上題
下面這段登入功能的 React component 有一些問題,請找到問題並修正
```javascript=
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import axios from 'axios';
import { actions } from 'service/action';
const LoginPage = () => {
const [account, setAccount] = useState();
const [password, setPassword] = useState();
const [isAccountValid, setAccountValidStatus] = useState(false);
const [isPwValid, setPwValidStatus] = useState(false);
const dispatch = useDispatch();
const login = () => {
const postData = { account, password };
axios.post('example.com/api/login', postData)
.then(res => {
if (res.data.result) {
history.push('example.com/home');
return axios.get(`example.com/api/get-user-data?userId=${res.data.userId}`)
}
throw new Error('login fail');
})
.catch(console.error);
}
const handleLogin = () => {
checkAccount();
checkPw();
login().then(res => {
dispatch(actions.setUserState(res.data));
});
}
const checkAccount = () => {
if (account.length >= 6) {
setAccountValidStatus(true)
} else {
setAccountValidStatus(false)
}
}
const checkPw = () => {
if (password.length >= 8) {
setPwValidStatus(true)
} else {
setPwValidStatus(false)
}
}
return (
<form>
<h1>LoginPage</h1>
<input type="text" value={account} onChange={e => setAccount(e.target.value)}></input>
<input type="password" value={password} onChange={e => setPassword(e.target.value)}></input>
{
isAccountValid && isPwValid
? null
: <p>Account or Password is invalid</p>
}
<button onClick={handleLogin}>Log In</button>
</form>
)
}
export default LoginPage;
```
:arrow_right: 核心概念,其實不需要宣告第10行和第11行這兩個 state
:::
#### [Jenny題] CORS 為什麼要先傳一個 Options(preflight 請求)? [東]
:::spoiler 解釋
#### CORS 與 preflight 簡介
CORS (Cross-Origin Resource Sharing) 是針對不同源的請求而定的規範,透過 JavaScript 存取非同源資源時,server 必須明確告知瀏覽器允許何種請求,只有 server 允許的請求能夠被瀏覽器實際發送,否則會失敗。
**瀏覽器在發送請求之前會先發送 preflight request (預檢請求),確認伺服器端設定正確的 `Access-Control-Allow-Methods`、`Access-Control-Allow-Headers` 及 `Access-Control-Allow-Origin` 等 header,才會實際發送請求。**
*使用 cookie 的情況下還需額外設定 `Access-Control-Allow-Credentials` header。*
<br >
#### Preflight Request (預檢請求)
Preflight request 是一個 http OPTIONS 方法,會帶有兩個 request header:`Access-Control-Request-Method` 和 `Access-Control-Request-Headers`。
#### Preflight Response
那收到 preflight request 時,Server 該做什麼呢?
Server 必須告訴瀏覽器:我允許的方法和 header 有哪些。因此 Server 的回應必須帶有以下兩個 header:
- `Access-Control-Allow-Methods`: 允許的 HTTP 方法。
- `Access-Control-Allow-Headers`: 允許的非「簡單」header。
**當瀏覽器看到跨來源請求的方法和 header 都有被列在允許的方法和 header 中,就表示可以實際發送請求了!**
:::
#### **[CSS]** CSS Specificity [若]
:::spoiler 解釋
> :bookmark:**CSS Specificity( CSS 的權重/優先權):套用在 DOM 上的樣式,互相覆蓋的權力。**
> 瀏覽器會通過權重來判斷哪些屬性值與一個元素最為相關,並在該元素上應用這些屬性值。
> 權重是基於不同種類的選擇器 (CSS selectors) 組成的比較規則。
> [color=#f24]
==**權重的計算**==

簡單來說,可以分成四個區塊,從左而右分別是
- inline CSS (例 **style="font-weight:bold"**)
- ID selectors (例 **#example**)
- Class selectors(例 **.example**)、屬性選擇器(例 **[type="radio"]**)和偽類(例 **:hover**)
- Type selectors(例 **h1**)、偽元素(例 **::before**)
這裡可以像 ip 一樣表示成四個數字:0-0-0-0。
這些數字是 CSS 的規則,越往左邊權重越大,而數字越大權重也越大。
> 舉例來說,如果今天樣式表只有寫:div { color:red; },所產生的數字就是:0-0-0-1;
> 如果今天寫成:body div div { color:red; },那麼數字就可以表示為:0-0-0-3;
> 如果今天寫成:#header div { color:red },那麼數字就要表示為:0-1-0-1;
> 而 0-0-0-3 一定會覆蓋過 0-0-0-1 ,0-1-0-1 會覆蓋過 0-0-0-3;
> 當然,如果兩個數字完全相同的,就是樣式擺放的比先後順序了。
> [color=#f24]
若還是有點不清楚,可以參考以下這兩張圖片:


==**例外規則 !important**==
``` css
/*範例:*/
table td { height: 50px !important; }
```
> 使用 !important 規則時,將會覆蓋其他的宣告。
> 雖然 !important 與權重無關,但它與最終的結果直接相關。
> 使用 !important 是一個壞習慣,應該盡量避免,因為這破壞了樣式表中的固有的規則,也使得debug變得困難了。
> [color=#f24]
==**小結**==

[繼續看更多補充](https://hackmd.io/EJje_7mjSsyjhpd66bT5bw#%E4%BE%8B%E5%A4%96%E8%A6%8F%E5%89%87-important)
:::
#### **[HTML]** 常用的 meta 標籤有哪些? [Natalia & Phoebe]
:::spoiler 解釋
* <meta> tag 用來描述 HTML 文件 (document) 的元資訊 (metadata),透過 <meta> 我們可以設定很多不同類型的網頁資訊。
* <meta> tag 是放在 <head> tag 裡面。
## 指定網頁所使用的編碼
<meta> charset 用來指定網頁內容是用什麼編碼 (character set)
```+
<meta charset="utf-8">
```
## 螢幕設定
當在設計RWD網頁時,我們需要用 <meta> viewport 來指定瀏覽器怎麼渲染和縮放網頁畫面的寬高。
```+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
```
* width=device-width 指定瀏覽器頁面的寬度同裝置 (device) 的寬度
* initial-scale=1.0 指定畫面初始縮放比例為 100%,即不放大也不縮小
* user-scalable=no,禁止用戶手動縮放網站,設定範圍:1(yes) / 0(no)
* minimum-scale=1,設定網站最小的縮放大小,設定範圍:0.25 ~ 5
* maximum-scale=1,設定網站最大的縮放大小,設定範圍:0.25 ~ 5
## 搜尋引擎
<meta> robots 標記針對特定網頁控管應如何將各個網頁納入索引並顯示在搜尋引擎的 (Google) 搜尋結果中。
```+
<meta name="robots" content="index, follow">
```
* index: 在搜尋結果中顯示這個網頁
* follow: 追蹤這個網頁上的連結
* all: 預設值,等同於 index, follow
* noarchive:告訴google不要保存含此標籤的網頁的快照
## 自動跳轉網頁
<meta> refresh 可以用來設定幾秒鐘後跳轉 (redirect) 到某一個 URL
```+
<meta http-equiv="refresh" content="5; url=https://www.example.com">
```
上面例子會讓網頁在載入 5 秒後,自動跳轉到https://www.example.com
如果設定content="0",對搜尋引擎來說就是 301 永久轉址的意思。參考這篇 [Answers to the SEO Professional’s Litmus Test ](https://moz.com/blog/answers-to-the-seo-professionals-litmus-test)第二點說明。
```+
<meta http-equiv="refresh" content="10">
```
如果不加 url 參數則是定時刷新頁面(指定每 10 秒就重整頁面一次)
## 網頁基本設定
```+
<title>網頁標題</title>
<meta name="description" content="網站描述">
<meta name="keywords" content="關鍵字1, 關鍵字2, 關鍵字3">
```
* title:網頁標題在 Google 搜尋引擎中顯示55-64 個字元,建議 60 字元以內
* keywords:搜尋此網站的關鍵文字(可用半型空格或逗點隔開)
* description:定義網站摘要,通常會出現在搜尋頁中的網站內容描述,建議 160 字以內
> Google SEO已經不看 meta keywords 的內容了,你可以將關鍵字放在 meta description 中。
[The Most Important Meta Tags For SEO in 2021](https://www.advancedwebranking.com/blog/meta-tags-important-in-seo/)

[rel="canonical" link 標記](https://developers.google.com/search/docs/advanced/crawling/consolidate-duplicate-urls?hl=zh-tw#rel-canonical-link-method)
## 外部連結分享設定
```+
<!-- 給 FB 看的屬性標籤 -->
<meta property="og:title" content="標題">
<meta property="og:description" content="描述">
<meta property="og:image" content="https://XXXX.com/image.jpg"
(網站預覽圖的 url)( url 一定要使用絕對路徑)(建議尺寸 1200x630)>
<!-- 給 Twitter 看的屬性標籤 -->
<meta name="twitter:title" content="標題">
<meta name="twitter:description" content="描述">
<meta name="twitter:image" content="https://XXXX.com/XXXX.jpg">
```

[fb網站管理](https://developers.facebook.com/docs/sharing/webmasters?locale=zh_TW)
seo補充:

:::
#### **[HTML]** Canvas和SVG的區別? [Natalia & Phoebe]
:::spoiler 解釋
## SVG
1. SVG(Scalable Vector Graphics)為一種可縮放向量圖形,是基於 XML的一種圖形格式。向量圖像由一組固定的形狀組成,在縮放時,圖像不會失真。
1. SVG 是基於形狀的保留模式圖形系統,繪製完物件後會將其儲存在記憶體中,當需要修改這個物件時,直接修改就可以了。
[SVG 完整教學 31 天](https://www.oxxostudio.tw/articles/201410/svg-tutorial.html)
## Canvas
1. Canvas 是一個 HTML 元素,利用javascript在這個元素上繪圖。
2. Canvas 是基於畫素的即時模式圖形系統,繪製完物件後不儲存物件到記憶體中,當再次需要這個物件時,需要重新繪製。
3. Canvas 適合像素處理,動態渲染和大數量繪製。
[Canvas 指令碼手冊](https://www.we-shop.net/html/html_ref_canvas.php)
## 實際應用
canvas 適合做圖像密集型的遊戲,可以快速頻繁地重繪圖像,所以大型遊戲開發都用 canvas 。統計中常見的柱狀圖、餅圖、雷達圖等也是使用 canvas 。
svg 繪制的是向量圖,放大後不會失真,適合具有大渲染區域的應用程序,所以很適合做地圖。
## 操作方面
canvas只能給整個畫布添加事件,而不能給某個圖形或文件添加事件處理器。
svg 支持事件綁定,如果需要添加帶有事件的動畫效果時,就選擇 svg。
## 保存格式
canvas 繪制的圖形可以多種格式 (jpg、png) 保存圖片。
svg 繪制的只能以 .svg 格式保存,使用時引入 html 文件。
[SVG 和其他格式的差異](https://www.oxxostudio.tw/articles/201406/svg-01-intro.html)

[HTML5(十)——Canvas 與 SVG 區別](https://qdmana.com/2021/08/20210816040618166S.html)
[SVG vs Canvas](https://www.educba.com/svg-vs-canvas/)
:::
---
### 九月第二週 報告日 9/11(六) 21:00 、9/12(日) 10:00
收單時間:9/9(四) 22:00
##### (六)
#### (YPO面試題)當在瀏覽器中的上方網址列中打上url後,發生了什事?[SOL]
:::spoiler 解釋

1. 您在網絡瀏覽器中輸入一個 URL
2. 瀏覽器通過DNS(Domain Name Systemj網路名稱系統)查找域名的IP地址
3. 瀏覽器向服務器發送一個 HTTP *request*
4. 服務器發回一個 HTTP *response*
5. 瀏覽器開始渲染 HTML
6. 瀏覽器發送對嵌入在 HTML 中的其他對象(圖像、CSS、JavaScript)的請求並重複步驟 3-5。
7. 頁面加載完畢後,瀏覽器會根據需要發送更多異步請求。
進行TCP連接(3次握手)
(1) 用戶端向伺服器發送請求是否可以建立鏈接
(2) 伺服器返回同意
(3)用戶端回饋伺服器的響應
:::
#### setTimeout()& setInterval()如果是inactive tab 瀏覽器會有怎樣的機制[SOL]
:::spoiler 解釋
#### 問題點
>實作番茄時中時,為了方便更快測試番茄時鐘的轉換時間變換,setInterval()是設定每100毫秒跑一次,但發現當我換到另一個分頁時,再回到番茄時鐘的分頁,發現時間顯示好像有變慢過,反覆確認程式是沒有問題的,再將setInterval()設定回每1000毫秒跑一次,咦?這就沒問題了,那為什麼會發生這樣的狀況呢?
#### 這是瀏覽器的一個機制
為了減少背景分頁(也就是你目前沒有在使用的分頁)的負載,瀏覽器會強制將背景分頁的setTimeout設定至他們最小能執行的延遲時間,對於Chrome,Firefox,Edge,Safari,Opera是1000毫秒,IE則沒有影響。
#### 最新有關於Background Tabs的更新,官方文件2017年 Chrome57版本:
> Background tabs can have a dramatic negative effect on browser performance, especially on battery life. To mitigate this, Chrome has been placing various restrictions on background tabs for the last several years. Recently there’s been a number of efforts to make further improvements, and this document gives an overview of the Chrome policy. This document focuses on describing current policies in Chrome 57.
背景頁面會對會對瀏覽器的性能造成很大的影響,尤其對電腦的電磁壽命,為了緩解這種情況,Chrome 一直在對背景標籤設置各種限制,並改善。
* Optimising an application for background
除非絕對有必要提供特定的用戶體驗,否則應將後台工作保持在最低限度。
有些網站使用Page visibility API,大幅降低幾乎75%的CPU使用量。他可以偵測網站是否被看見。
```javascript=
document.addEventListener("visibilitychange", function () {
console.log(document.visibilityState, "---------");
});
```
* Policies
1. requestAnimationFrame(), 背景頁面不會被呼叫。
2. Background timer alignment 後台定時器對齊,每個獨立計時器每秒運行不超過一次。Chrome 每秒分批運行一次這些計時器,確保將進程喚醒次數保持在最低限度。 播放可聽音頻的頁面被認為是用戶可見的,並且不受後台計時器限制。音頻停止播放後,豁免會持續幾秒鐘,以允許應用程序將下一個音軌排入隊列。
請注意,當且僅當 Chrome 顯示音頻圖標時,音頻才被認為是可聽的。 靜音音頻流不授予豁免。
3. Budget-based background timer throttling 時間節流的細節,有興趣可到官網看
4. 你也可以到設定中取消或使用這個機制-disable-background-timer-throttling
chrome://flags/#--disable-background-timer-throttling
> Chorme 就是吃電磁的怪獸XD
[Google Chrome ships a new feature to increase Battery life by 28 percent to 2 hours](https://news.thewindowsclub.com/google-chrome-ships-a-new-feature-to-increase-the-battery-life-101417/)
36個背景分頁 ,前分頁只是about:blank 一個空白分頁

### 兩種可能豁免次限制
1. 播放音樂時不會被當作背景頁面。
2. 有real-time connections (WebSockets and WebRTC)
:::warning
突然發現我專案中的番茄時鐘就是個廢物XD
現實中跑了11分鐘整,番茄時鐘才跑19:51,才給我跑5分9秒?? 應該要是5分6秒啦,因為超過五分中後一秒會變成一分鐘🙌💩。
:::
連結:
[Background Tabs in Chrome 57 ](https://developers.google.com/web/updates/2017/03/background_tabs)
[MDN setTimeout()](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout)
:::
---
:::spoiler useEffect的作用跟相對應的功能[蓁]
> useEffect, 生命週期, cleanup, useLayoutEffect
[useEffect的作用跟相對應的功能](https://hackmd.io/dVjjmRJbRnWU56pbv5aOCQ)
:::
:::spoiler set & New` 關鍵字題目[月]
set:https://hackmd.io/RgXYRlCFTp6jwBkmYEfq9w
```javascript=
// New 關鍵字題目
function Car() {
this.make = 'Lamborghini';
return { make: 'Maserati' };
}
const myCar = new Car();
console.log(myCar.make); // Maserati
```
:::
#### 資料安全、單向雙向資料流、strong&b [Raiy]
:::spoiler
* 資料安全
https://hackmd.io/S5E9myIxQHm5qhQWpgkqvg
* 單向雙向資料流
https://hackmd.io/PdYzViY1QZ6INSQ7V2_EPQ?view
* 標籤 strong、b 差異( i em s del)
https://hackmd.io/we5UByXxQiSIGvEAdNwFrw
:::
##### (日)
#### Git / GitHub:`git pull` v.s. `git fetch`
#### Git 版本控制: `git reset`, `git rebase`[東]
:::spoiler 解釋
[Git / Github 常用進階指令
](https://hackmd.io/F3DL12ZOQ3urW8fl1RsNNA)
:::
#### 什麼是 GraphQL ? 跟 RESTful APIs 的比較? [東]
:::spoiler 解釋
[GraphQL 簡介 / GraphQL v.s. RESTful APIs
](https://hackmd.io/IMYRkw6VRjOdmS1otkNl3A)
:::
#### 陣列排序 sort() [若]
:::spoiler 解釋
| 標題 | 解釋 |
| -------- | -------- |
| 原型 |Array.prototype.sort()|
| 功能 |依據字串的 [Unicode](http://www.tamasoft.co.jp/en/general-info/unicode.html) 編碼進行排序|
| 回傳值 |回傳排序後的陣列(不是原陣列的拷貝)|
| 語法 |arr.sort([compareFunction])|
| 參數 |預設排序:依據字串的 Unicode 編碼進行排序。<br/>自定義排序:可指定比較函式來定義排序的順序。|
使用sort()的時候,數字會轉換成字串(number.toString() )後才做排序。
**預設排序(Default sort)**
```javascript=
const arr1 =["apple", "Banana", "coco", "Ege"];
console.log(arr1.sort());
// output: ["Banana", "Ege", "apple", "coco"]
const arr2 = [1, 30, 4, 21, 100];
console.log(arr2.sort(););
// output: [1, 100, 21, 30, 4]
// 因字串 '100' 的第一個字元 '1' 比 '2' 的 Unicode code point 小
```
**自定義排序 (Custom Sort)**
sort() 可以傳入函數參數 compareFunction,可以用來自訂排序的邏輯,陣列會根據 compareFunction 函數的回傳值來做排序依據。

例子:
```javascript=
// 升序
const arr1 = [45, 42, 10, 147, 7, 65, -74];
console.log(
arr1.sort(function(a, b) {
return a - b;
})
);
// output: [-74, 7, 10, 42, 45, 65, 147]
//
// 降序
const arr2 = [45, 42, 10, 111, 7, 65, -74];
console.log(
arr2.sort(function(a, b) {
return b - a;
})
);
// output: [111, 65, 45, 42, 10, 7, -74]
// json物件 利用屬性排序
const arr3 = [{id:10},{id:5},{id:6},{id:9},{id:2},{id:3}];
console.log(arr3.sort(function(a,b){
return a.id - b.id
}))
// output: {id: 2} {id: 3} {id: 5} {id: 6} {id: 9} {id: 10}
```
題目:
```javascript=
const arr1 = ['a', 'b', 'c'];
const arr2 = ['b', 'c', 'a'];
console.log(
arr1.sort() === arr1,
arr2.sort() == arr2,
arr1.sort() === arr2.sort()
);
// true, true, false
```
:::
#### (小哥題) SASS?SCSS ? & 代表什麼?[Natalia & Phoebe]
:::spoiler 解釋
* Sass是一個將指令碼解析成CSS的手稿語言,即SassScript
* Sass 會**編譯**(compiled)程式碼,轉成一般 CSS 形式,讓瀏覽器可以解讀輸出呈現畫面
* Sass 是一個 css 預處理器(CSS preprocessor)
* 管理CSS的工具的程式語言,有兩種格式寫法: 1.SCSS 2.Sass

## CSS 預處理器(CSS preprocessor)
* CSS 語法的擴充
* 為彌補 CSS 在大型專案維護性的不足,CSS 預處理器中新增了變數、混入、繼承、嵌套等寫法,讓開發者可以更有結構地撰寫簡潔、清晰且好維護的 CSS 程式碼。
* CSS 預處理器相對於 CSS 算是較高階的語法,需要另外**編譯**成 CSS,瀏覽器才看得懂
> CSS都寫在SCSS檔案裡面
> SCSS / Sass檔名開頭為底線 _ 不編譯為CSS檔

## Sass
2007 年誕生的 Sass,是最早的 CSS 預處理器
縮排式的寫法,不寫大括號及分號
縮排的風格可以減少程式碼,但**無法兼容舊有的 CSS 語法**
## SCSS
後來受到 Less 影響,Sass 發展出兼容 CSS 的新語法就稱為 SCSS
有大括號及分號,較接近原始CSS的語法
擴充變數、巢狀、mixins、extend、運算符、import等功能
## & 連接符號
* 選擇器用**&符號接起父層**
如果想在嵌套狀態下,取得外層的父選擇器,可以使用「 & 」。
1. 常會把它用在,如 CSS 元件狀態: :hover、:focus、:link、:visited 等 ..,或是 :before、:after

2. 還有另一種用法,如下:

> Boostrap 就是以Sass編譯而成的插件
[SCSS教學](https://frankknow.com/SASS-tutorial/#subject-2)
:::
#### (小哥題)水平垂直置中的不同方法[Natalia & Phoebe]
:::spoiler 解釋
https://hackmd.io/@pikachuchu/Hk5CPlwfF
:::
---
### 九月第三週 報告日 9/18(六) 21:00 、9/19(日) 10:00
收單時間:9/17(五) 22:00
##### (六)
#### 面試機上題,setInterval效能優化(useRef) [SOL]
:::spoiler 問題
#### 問題一:下面的程式碼畫面會如何呈現?
```javascript=
import React, { useState, useEffect } from "react";
const Count = function () {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count + 1);
}, 1000);
return () => {
clearInterval(id);
};
}, []);
return <p>{count}</p>;
};
export default Count;
```
它會開始計數,之後停在 1 。這個奇怪的行為怎麼發生的?把 log 放在 setInterval 當中會發現這個 輪循一直有在跑。可是它的 count 一直是0。因為這個 useEffect 只在 first render 的時候執行了一次,setInterval 裡面的 closure 參照的是 first render 的 count ,就是0 。簡單調整的作法有兩種,第一種是在第二個參數本來是空陣列裡面加 count。這樣它會去比對 count。如果 count 不一樣就會執行useEffect,這時候 count 參照的值會是新的了。第二種是 在 setCount() 裡面傳 count => count + 1。這樣 count 參照的會是最新的 state,且不會重新執行 useEffect,只會執行 setInterval。
#### 問題二:如何讓他呈現一直累加並render在畫面上?
```jsx
import React, { useState, useEffect } from "react";
const Count = function () {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount(count + 1);
}, 1000);
return () => {
clearInterval(id);
};
}, [count]);
return <p>{count}</p>;
};
export default Count;
```
#### 問題三:加上dependencies後,會在畫面重新render時,UseEffect中的程式碼會一直被重複呼叫,也就代表setInterval 和 clearInterval 一直被重新設定,這部分可以如何執行效能優化?
- useRef 回傳一個 mutable 的 ref object,.current 屬性被初始為傳入的參數(initialValue)。
`const div = useRef({})` 這邊的`{}` 會被設定為初始值放進current裡,divc回傳的是`{current:{}}`
==本質上,useRef 就像一個可以持有 mutable 的值在 .current 屬性的「盒子」==
- 主要是用來訪問 DOM 的方式,但useRef() Hook 不只是針對 DOM 的 ref。「ref」object 是一個 generic container,其 current 屬性是可變的,可以保存任何值。這是因為 `useRef()` 會建立一個普通的 JavaScript object。`useRef()` 和自建一個 `{current: ...}` object 的唯一不同是,`useRef` 在每次 render 時都會給你同一個的 ref object。
- 請記住 `useRef` 在其內容有變化時並*不會*通知你。變更 `.current` 屬性不會觸發重新 render。如果想要在 React 綁定或解綁 DOM 節點的 ref 時執行程式碼,你可能需要使用 [callback ref](https://zh-hant.reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node) 來實現。
#### 參考:
[CODE實作連結](https://codesandbox.io/s/ji-shang-ti-d4t10?file=/src/CountOptimized.js)
[使用 React Hooks 宣告 setInterval](https://iter01.com/136040.html)
[Making setInterval Declarative with React Hooks](https://overreacted.io/making-setinterval-declarative-with-react-hooks/)
==useRef 並不會觸發 re-render,所以你的值存在 useRef 裡,就算資料更新了畫面也不會更新。==
:::
蓁 - 使用 useCallback、useMemo、useReducer 優化效能的時機
:::spoiler 效能優化
[效能優化:useCallback、useMemo、useReducer](https://hackmd.io/ulFazTCqQGKRpVDkPHIr4A)
:::
月 - [Sass, SCSS](https://hackmd.io/YzMEKL0DSfOjZMO1XiA20g)
Raiy - 瀏覽器引擎&瀏覽器相容性 (包括 js css)
##### (日)
#### 如何處理不同裝置,尤其是不同畫質的行動裝置上, dpi 不同的問題 [東]
:::spoiler 關於 dpi 的介紹
**dots per inch** : 一英寸多少個像素点。一般稱作像素密度(類似密度)
[前端開發基礎知識 dpi 、 dip 、分辨率、屏幕尺寸、px、density 關係以及換算](https://blog.csdn.net/clirus/article/details/50807855)
[參考:各種裝置的 dpi 對照表
](https://dpi.lv/)
:::
#### GraphQL 實作 [東]
(待補)
---
### 九月第四週 報告日 9/25(六) 21:00 、9/26(日) 10:00
收單時間:9/24(五) 22:00
##### (六)
蓁(講第三週內容)
月(講第三週內容)
##### (日)
#### [css]ul li inline-block的空白問題[若]
:::spoiler
```htmlmixed=
<body>
<ul>
<li>香蕉</li>
<li>蘋果</li>
<li>橘子</li>
</ul>
</body>
<style>
ul {
list-style: none;
}
li {
display: inline-block;
background-color: orange;
}
</style>
```

原因:
瀏覽器的默認行為是把 inline 元素間的空白字符(空格換行 tab)渲染成一個空格,換行後會產生換行字符,而它會變成一個空格,因此空格就佔用一個字符的寬度。
解決方法:

1. 更改結構,把 li 寫到同一行
```htmlmixed=
<ul>
<li>香蕉</li><li>蘋果</li><li>橘子</li>
</ul>
```
2. 設置負的letter-spacing
```css=
ul {
list-style: none;
letter-spacing: -5px;
}
li{
display: inline-block;
background-color: orange;
letter-spacing: normal;
}
```
3. css改成 float: left
```css=
ul {
list-style: none;
}
li{
display: inline-block;
background-color: orange;
float: left;
}
```
**ul list 去掉前面的空白**
大多數的瀏覽器會將`li`元素以`display: list-item`呈現。
list-item 關鍵字使元素生成一個 ::marker 偽元素,例如由其列表樣式屬性(例如項目符號)指定的內容。
可以用以下方式將樣式屬性的空白移除:
```css=
ul {
list-style: none;
padding: 0;
margin: 0;
}
```
:::
#### [css]關於px/rem/em[Natalia & Phoebe]
:::spoiler 解釋
* px:絕對單位,代表螢幕中每個「點」( pixel )。
* em:相對單位,每個子元素透過「倍數」乘以父元素的 px 值。(比例會受到外層父元素影響)
* rem:相對單位,每個元素透過「倍數」乘以根元素的 px 值。(比例會依照最外層的 html 標籤影響)
* %:相對單位,每個子元素透過「百分比」乘以父元素的 px 值。
```+
(1)px
<div style="font-size:16px;">16px
<div style="font-size:20px;">20px
<div style="font-size:24px;">24px
<div style="font-size:16px;">16px
<div style="font-size:32px;">32px</div>
</div>
</div>
</div>
</div>
(2)em:
相對單位,為每個子元素透過「倍數」乘以父元素的 px 值,如果我們每一層 div 都使用 1.2em,
最內層就會是16px x 1.2 x 1.2 x 1.2 x 1.2 x 1.2 = 39.8px。
( 瀏覽器預設字體大小為 16px,若無特別指定則會直接繼承父元素字體大小 )
<div style="font-size:1.2em;">1.2em
<div style="font-size:1.2em;">1.2em
<div style="font-size:1.2em;">1.2em
<div style="font-size:1.2em;">1.2em
<div style="font-size:1.2em;">1.2em</div>
</div>
</div>
</div>
</div>
(3)rem:
相對單位,為每個元素透過「倍數」乘以根元素的 px 值,如果我們每一層 div 都使用 1.2rem,
最內層就會是16px x 1.2 = 19.2px。
( 根元素指的是 html 的 font-size,預設為 16px )
<div style="font-size:1.2rem;">1.2rem
<div style="font-size:1.2rem;">1.2rem
<div style="font-size:1.2rem;">1.2rem
<div style="font-size:1.2rem;">1.2rem
<div style="font-size:1.2rem;">1.2rem</div>
</div>
</div>
</div>
</div>
(4)%:
相對單位,和 em 大同小異,為每個子元素透過「百分比」乘以父元素的 px 值,如果我們每一層 div 都使用 120%,就等同於 1.2em,
最內層就會是16px x 1.2 x 1.2 x 1.2 x 1.2 x 1.2 = 39.8px。
<div style="font-size:120%;">120%
<div style="font-size:120%;">120%
<div style="font-size:120%;">120%
<div style="font-size:120%;">120%
<div style="font-size:120%;">120%</div>
</div>
</div>
</div>
</div>
```

## 視窗單位
* viewpoint height (vh)
可視區 (viewport) 的高度 (px) ,除以 100 ,等於 1vh
* viewpoint weight (vw)
可視區 (viewport) 的寬度 (px) ,除以 100 ,等於 1vw
> 瀏覽器高度900px,寬度為750px, 1 vh = 900px/100 = 9 px,1vw = 750px/100 = 7.5 px。
> 「手機的 1vw 」≠「 桌機的 1vw 」≠「 筆電的 1vw 」

* vmin:當前 vw 和 vh 中較小的一個值
* vmax:當前 vw 和 vh 中較大的一個值
## vmin & vmax用處?
* 靈活運用可以減少css程式碼
1.製作RWD時,如果使用 vw、vh 設置字體大小(比如 5vw),在直屏和横屏顯示的字體大小是不一樣的,但若使用vmin與max則可使文字在直橫屏一致。
2.有一個元素,你需要讓它在屏幕上始終可見:
```+
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
<title></title>
<style>
*{margin:0; padding:0;}
.box {
height: 100vmin;
width: 100vmin;
background:red;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
```

如果要讓這個元素始終鋪滿整個視口的可視區域,只需要把上面的vmin改成vmax即可
```+
.box { height: 100vmax; width: 100vmax; background:red;}
```

:::
:::spoiler Intersection Observer API [SOL]
[LINK](https://bush-danthus-f0a.notion.site/Intersection-Observer-API-a8c10934945f4f08bc3cd5190905b5d2)
[code](https://codesandbox.io/s/observer-api-kseo5?file=/src/index.js)
:::
---
### 十月第一週 報告日 9/25(六) 20:30
收單時間:9/24(五) 22:00
#### `git fetch`, `git reset`, `git rebase` 的實作 [東]
:::spoiler 解釋
:::
#### [GraphQL 前端實作](https://hackmd.io/VtarD-t1TiCkZWUKCOUrzQ) [東]