[6분] useEffect

useEffect는 렌더링 후에, 컴포넌트가 뭘 해야 하는지를 알려주는 부분 입니다. 렌더링이 되고 난 후에, 이 부분에 작성한 함수들이 실행이 되게 됩니다.
주로 이 영역을 통해서 API 콜을 하여 데이터를 받아오거나, 이벤트 리스너 같은 것들을 등록합니다.
아래처럼 말이죠.
const App = () => { const [someState, setSomeState] = useState(""); useEffect(() => { axios.get('/user/12345') .then(response => { //do something here such as setState setSomeState(response) //for instance, }) }, []) const handleUserKeyPress = (evt) => { //do something here } useEffect(() => { window.addEventListener('keydown', handleUserKeyPress); }, []) return <> <span>hello</span> <span>{someState}</span> </> }
JavaScript
이렇게 하면
처음에 hello가 보이고, 그다음 api콜을 통해 정보를 받아온 다음 someState가 response값으로 업데이트 되면서 최종적으로 밑에서 보이게 됩니다.
또한, 병렬적으로 useEffect를 또 설치할 수도 있습니다. 여기서 윈도우에 리스닝 이벤트를 추가 했습니다. 한가지 문제가 있다면, 이상태로 다른 페이지를 간다면, 계속해서 keydown 리스너가 동작을 할겁니다. window 에 등록이 되는 거죠. 따라서 우리는 이 페이지 말고 다른 곧으로 갈때는 등록해둔 listener를 해지 할겁니다. 방법은 아래와 같습니다.
const handleUserKeyPress = (evt) => { //do something here } useEffect(() => { window.addEventListener('keydown', handleUserKeyPress); return () => { window.removeEventListener('keydown', handleUserKeyPress); }; }, [])
JavaScript
잘 확인해보시면, useEffect내에 등록과 해제가 둘다 작성 되어 있는 것을 볼 수 있습니다. return 부분에 함수형태
() => {something here}
JavaScript
이부분이 해당 페이지가 unmount될 때에 실행이 됩니다.

"또" 다른 예를 한 번 볼까요?

useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); // Specify how to clean up after this effect: return function cleanup() { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }, []);
JavaScript
friendStatus를 섭스크라입하는 것이 실행이 되었다가, cleanup타임이 오면 언섭스크랍입을 해주는 것을 잊으면 안된답니다.
자 이제 마무리로 하나만 더!
처음 렌더링되고나서 최초 한 번 실행말고, 특정 스테이트가 바뀔 때마다 실행이 되게끔 한 번 useEffect를 디자인해보겠습니다. 예를 들어, cnt 스테이트가 증가할 때마다, alert을 띄워보고 싶습니다.
const [cnt, setCnt] = useState(0); useEffect(() => { alert('!') }, [cnt]); return <> <div onClick={e => {setCnt(cnt => cnt + 1)}}>+1</div> </>
JavaScript
useEffect안에 bracket [cnt]가 보이시나요? 이 부분을 dependency라고 부르는데, 이게 뭐냐면, cnt가 변하면, 이 useEffect를 실행하라!이런 말입니다.
이 dependency에는 여러가지를 넣을 수가 있어요 이렇게요.
const [cnt, setCnt] = useState(0); const [otherState, setOtherState] = useState(1); useEffect(() => { alert(`${cnt}-${otherState}`) }, [cnt, otherState]); return <> <div onClick={e => {setCnt(cnt => cnt + 1)}}>+1</div> <div onClick={e => {setOtherState(otherState => otherState + 1)}}>+1</div> </>
JavaScript
otherState가 1씩 증가해도 alert이 뜨고, cnt값이 바뀌어도 alert이 뜹니다. 값도 업데이트가 되는 것을 확인할 수 있습니다. (꼭 한 번 해보세요!)

주로 하는 실수가 있도다!

const [cnt, setCnt] = useState(0); useEffect(() => { setInterval(() => { alert(cnt) }, 1000) }, []); return return <> <div onClick={e => {setCnt(cnt => cnt + 1)}}>+1</div> </>
JavaScript
자 위의 코드를 보시면, 최초 랜더링이 되고, 그다음 useEffect를 통해 setInterval이 등록이 됩니다. 1초 마다 cnt를 얼럿해주죠. 처음에0이나오고, 또 1초후에 0, 또 0초 후에 0.
자이제 +1을 눌러서 cnt를 증가 시켜 봅시다. 그러면 alert은 1,2,3,4,.. 이렇게 될까요?
정답은 땡! 입니다.
이유는, 처음에 useEffect에서 []로 등록을 할 때의 cnt는 초기값 0때문이죠.
그렇다면, 우리가 클릭을 할 때에, cnt값이 바뀌어서 setInterval에서 alert으로 나오게 어떻게 할까요?
숙제입니다.!