리액트가 하는 일은 무언가를 화면으로 가져오는 일이다. 리액트는 함수를 실행하고 각 컴포넌트들은 함수로 이루어져 있다.
HTTP 리퀘스트를 보내는 일과 응답을 받는 일은 화면으로 가져오는 일과 전혀 관계가 없다. 이런 리액트가 하는 일들이 아닌것들을Side Effect
라고 한다.
다음과 같은 간단한 로그인 페이지가 있다. 이메일과 패스워드를 입력해서 로그인을 할 수는 있지만 재접속을하면 로그인이 풀려있다. 이 문제를 해결하기 위해선 로컬스토리지를 이용해서 로그인 정보를 저장해주면 된다.
로그인이 성공했을 때 localStorage.setItem("isLoggedIn", "1");
을 이용하여 로그인 정보를 저장해 준다.
페이지가 로딩될 때 로그인이 되어있는지 확인하는 변수를 만들어준다.
const storeUserLoggedinInformation = localStorage.getItem("isLoggedIn");
로컬 스토리지의 정보를 바탕으로 로그인 상태를 결정한다.
if (storeUserLoggedinInformation === "1") {
setIsLoggedIn(true);
}
이렇게 하면 될것 같지만 되지 않는다. 로그인 정보가 있다면 State
가 변하게 되고 State
가 변하면 다시 App
이 렌더링 된다. App
이 렌더링되면 다시 State
가 변하고 그렇게 무한루프에 빠져버리는 것이다.
따라서 useEffect
를 사용해야 한다.
useEffect( function , dependency )
처럼 사용하는데
useEffect( ()=>{} , [] )
와 같다. 하지만 디펜던시가 뭔지는 아직 잘 모르겠다.
어쨌든, useEffect
내부는 디펜던시가 변했을 때만 실행된다고 했으므로 다음과 같이 코드를 바꾸자.
useEffect(() => {
const storeUserLoggedinInformation = localStorage.getItem("isLoggedIn");
if (storeUserLoggedinInformation === "1") {
setIsLoggedIn(true);
}
}, []);
localStorage.removeItem("isLoggedIn");
까지 하면 우선 로그인 기능은 수행할 수 있다.useEffect( function , dependency )
여기 들어있는 function
은 컴포넌트가 전부 렌더링 된 이후에 실행된다.
useEffect( function , [] )
디펜던시를 비워둘 경우 한번만 실행되고 다시 실행되지 않는다.
useEffect( function , [variable] )
디펜던시에 variable
을 넣었을 경우 해당 변수의 상태가 바뀔 때마다 function
을 실행한다.
로그인을 할 때 이메일 형식이 맞는지, 그리고 패스워드의 형식이 맞는지 검사하는 Validate 함수가 있을 것이다. 그런데 키가 입력될 때마다 유효성을 검사해준다면 상당히 비효율적일 것이다. 여기서는 물론 느려지지 않겠지만
HTTP request
를 한다고 생각하면 키 입력이 이루어질 때마다 서버 통신을 하게 되는 셈이다.
따라서 이번 clean-up 함수를 이용하는 목적은 일정시간동안 입력을 하지 않았을 때 한번만 유효성을 검사하도록 만드는 것이다.
다음과 같은 코드를 짰을 때는 이전과 마찬가지로 키 입력이 이루어질 때마다 유효성을 확인하게 된다.
useEffect(() => {
setFormIsValid(
enteredEmail.includes("@") && enteredPassword.trim().length > 6
);
console.log("유효성 확인");
}, [enteredEmail, enteredPassword]);
setTimeout
문을 사용하면 1초씩 늦게 반응하지만 모든 키 입력마다 유효성을 확인한다. setTimeout(() => {
setFormIsValid(
enteredEmail.includes("@") && enteredPassword.trim().length > 6
);
console.log("유효성 확인");
}, 1000);
return
문을 활용할때 clean up function
이라고 부른다. 1초안에 키 입력이 이루어지면 리턴문이 실행되고 이전에 켜놓았던 타이머가 꺼진다. 따라서 키입력이 있는동안에는 유효성검사를 하지않고, 1초간 키입력이 없는 다음에야 유효성 검사를 하게 되는 것이다. 이렇게 하면 클린업 함수가 돌아갈 때마다
클린업 함수가 돌아가기 전에 설정된
타이머를 클리어할 수 있습니다.따라서 마지막 사이드 이펙트 함수가 실행되면
다음 사이드 이펙트가 실행될 때
새 타이머를 설정할 수 있습니다.따라서 새로운 걸 설정하기 전에 마지막 타이머를 클리어 합니다.
useEffect(() => {
const lateFunction = setTimeout(() => {
setFormIsValid(
enteredEmail.includes("@") && enteredPassword.trim().length > 6
);
console.log("유효성 확인");
}, 1000);
return () => {
clearTimeout(lateFunction);
console.log("CLEAN-UP");
};
}, [enteredEmail, enteredPassword]);
첫 실행시에 function
이 실행된다.
두번째 실행부터 return
문 부터 실행된다. (clean up)
그리고 function
이 실행된다.
Component
가 제거될 때 return
문이 실행된다. (로그인 시)