# React Hook - useEffect ###### tags: `Javascript, React` # useEffect 使用時機 > 不管是當畫面首次 render ,或是畫面 unmount 或是變數/ state / props 改變,或是任何的更新,你想要 side effect 發生就是使用 useEffect 的好時機 為了展示 useEffect 的效果,當點擊下方按鈕後會串接到 jsonplaceholder 內部的資料 ![](https://i.imgur.com/z6YboqR.png) jsonplaceholder 內部的 endpoint 可以串接的資料 ![](https://i.imgur.com/f6jQpbd.png) 程式碼: 簡單的使用 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 ![](https://i.imgur.com/YfRPYBV.png) ### 第二個參數讓它可以監聽特定對象 比方說我們放入 resourceType 那 useEffect 就只會在放入的參數有”改變“時才會被觸發,這也是比較常用到的情景 ```javascript= useEffect(() =>{ console.log('render') },[resourceType]) ``` 如果放入為空陣列則只會在畫面第一次出現時會觸發(onMount),其他任何時候都不會,因為它監聽的東西為空永遠都不會改變 ```javascript= useEffect(() =>{ console.log('render') },[]) ``` ### useEffect 取得資料 直接使用其官網給的範例使用 ![](https://i.imgur.com/h6Py5bV.png) 修改最後的 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> ); } ``` 即可印出內容摟 ![](https://i.imgur.com/kpNd0Wc.png) ## 較複雜的 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. 事件監聽的情況下,停止聽監聽,保證每次動作完就清理掉