# React Hook - useEffect
###### tags: `Javascript, React`
# useEffect 使用時機
> 不管是當畫面首次 render ,或是畫面 unmount 或是變數/ state / props 改變,或是任何的更新,你想要 side effect 發生就是使用 useEffect 的好時機
為了展示 useEffect 的效果,當點擊下方按鈕後會串接到 jsonplaceholder 內部的資料

jsonplaceholder 內部的 endpoint 可以串接的資料

程式碼:
簡單的使用 useState 呈現點擊按鈕後的內容在 h1 tag 內,之後會使用 useEffect 來真實的串接到 jsonplaceholder 內的資料
```javascript=
function App() {
const [resourceType, setResourceType] = useState('post');
useEffect(() =>{
console.log('render')
})
return (
<div className="App">
<button onClick={() => setResourceType('posts')}>posts</button>
<button onClick={() => setResourceType('users')}>users</button>
<button onClick={() => setResourceType('comments')}>comments</button>
<h1>{resourceType}</h1>
</div>
);
}
```
## 簡單示範 useEffect 功能
### useEffect 會在每次畫面 render 的時候觸發
1. 第一個 render 發生在整個畫面出現的時候
2. 第二次之後的則都是我點按鈕觸發的 render

### 第二個參數讓它可以監聽特定對象
比方說我們放入 resourceType 那 useEffect 就只會在放入的參數有”改變“時才會被觸發,這也是比較常用到的情景
```javascript=
useEffect(() =>{
console.log('render')
},[resourceType])
```
如果放入為空陣列則只會在畫面第一次出現時會觸發(onMount),其他任何時候都不會,因為它監聽的東西為空永遠都不會改變
```javascript=
useEffect(() =>{
console.log('render')
},[])
```
### useEffect 取得資料
直接使用其官網給的範例使用

修改最後的 endpoint 讓其動態呈現 resourceType 的 state ,就可以實現點擊按鈕時觸發不一樣的內容,針對 fetch 到的內容設定到 items 裏面
```javascript=
useEffect(() =>{
fetch(`https://jsonplaceholder.typicode.com/${resourceType}`)
.then(response => response.json())
.then(json => setItems(json))
},[resourceType])
```
接下來就 map items 到 畫面上即可
```javascript=
function App() {
const [resourceType, setResourceType] = useState('posts');
const [items, setItems] = useState([]);
useEffect(() =>{
fetch(`https://jsonplaceholder.typicode.com/${resourceType}`)
.then(response => response.json())
.then(json => setItems(json))
},[resourceType])
return (
<div className="App">
<button onClick={() => setResourceType('posts')}>posts</button>
<button onClick={() => setResourceType('users')}>users</button>
<button onClick={() => setResourceType('comments')}>comments</button>
<h1>{resourceType}</h1>
{items.map((item) =>{
return <pre>{JSON.stringify(item)}</pre>
})}
</div>
);
}
```
即可印出內容摟

## 較複雜的 useEffect 展示
下面程式碼的功能在於當你縮放你的瀏覽器時,畫面上的數字 `{windwWidth}` 會隨之改變,簡單來說就是動態的展示你的螢幕寬度的意思
作法就是藉由 useEffect 監聽 [] 空白陣列的效果,也就是每次畫面第一次更新的時候監聽 windowWidth,因為處理都設置在 初始值 也就是 useState 內,所以目前的改變都是!因此可以在每一次的的 windowWidth 改變都更新畫面摟!
```javascript=
function App() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const handleResize = ()=>{
setWindowWidth(window.innerWidth)
}
useEffect(() =>{
window.addEventListener('resize', handleResize)
},[])
return (
<div className="App">
{windowWidth}
</div>
);
}
```
然而當我們使用事件監聽 addEventListener ,當我們不需要使用時就必須清理掉它不然會造成效能被拖慢
不過操作上很簡單只要 return 一個 function 操作 removeEventListener 即可在每次 onMount 操作結束後,他就會 remove 當前的事件監聽摟!
```javascript=
useEffect(() =>{
window.addEventListener('resize', handleResize)
return () =>{
window.removeEventListener('resize', handleResize)
}
},[])
```
這個 clean up 的應用情景通常會是
1. fetch API 時,你做了下一個動作,這時候這個 clean up 就很好用會直接幫你終止這個 fetch 不會一直監聽它浪費效能
2. 事件監聽的情況下,停止聽監聽,保證每次動作完就清理掉