React 라이브러리 자체의 주요 임무는 사용자의 입력에 반응하여 필요할 때 UI를 다시 Rendering하는 것이다.
사용자의 입력에 state가 변경되거나 Event가 발생 될 때 화면에 가져와 사용자와 상호 작용하는 것이 React의 주 임무인 것이다.
화면에 보이는 것은 특정 이벤트에 따라 변경될 수 있다.
예를 들어, 버튼이 클릭되거나 인풋에 텍스트가 입력되는 것들이 있을 수 있다.
리액트를 구성하는 컴포넌트는 단지 함수이다.
따라서 위에서부터 아래로 실행된다.
함수 안에 있는 모든 것은 결국 함수에 입력된 값을 화면에 가져 오는 것을 말한다.
컴포넌트에 있는 모든 것은 화면에 무언가를 가져오는 것과 관련이 있다.
따라서 Side Effect란 어플리케이션에서 일어나는 모든 것을 뜻한다.
예를 들면 httpRequest를 보내거나 브라우저 저장소에 무언가를 저장하거나, 코드에서 타이머나 간격을 설정할 수도 있다.
이것들은 모두 어플리케이션에서 고려해야 하는 작업이다.
예를 더 들자면, 웹 어플리케이션은 대부분 백앤드 서버에 httpRequest를 보낸다.
그러나 이러한 작업은 화면에 무언가를 가져오는 것과 직접적인 관련이 없다.
물론 http Request를 보내어 응답을 받았을 때 화면에 무언가를 그릴 수 있다.
그러나 Request를 보내는 것 자체나 잠재적 오류를 처리하는 것 등은 리액트를 필요로 하는 것이 아니며 리액트가 신경쓰는 것이 아니다.
따라서 이것들은 일반적인 컴포넌트 평가 밖에서 일어나야 하는 일이다.
컴포넌트를 구성하는 함수는 컴포넌트 함수의 state가 변경될 때마다 리액트에 의해 자동으로 재실행 된다.
어떤state가 바뀔 때마다 이 전체 함수는 재실행된다는 것이다.
그리고 리액트는 기본적으로 함수를 새로 실행한 결과를 확인하여 새 JSX 코드가 어떻게 보이는지 확인한다.
이전 결과와 비교하고 실제 DOM으로 이동하여 약간의 변경을 진행한다.
이것이 리액트가 하는 일이다.
http Request에 대한 Response로 어떤 state를 변경한다면 무한 루프로 빠질 수도 있다.
왜냐하면 함수가 다시 실행될 때마다 Request를 보내면 그에 대한 Response로 함수를 다시 트리거하는 state를 변경하게 되기 때문이다.
따라서 이런 Side Effect는 직접적으로 컴포넌트 함수에 들어가서는 안된다.
이런 Side Effect를 관리하기 위해서 React에서는 useEffect라는 Hook을 제공한다.
useEffect Hook은 두 개의 매개변수, 두 개의 인수와 같이 호출된다.
첫 번째 인수는 함수다. 모든 컴포넌트 평가 후에 실행되어야 하는 함수이다.
그리고 두 번째 인수로는 의존성으로 구성된 배열이다.
의존성 배열 내 값이 변경될 때마다 첫 번째 함수가 다시 실행된다.
따라서 첫 번째 함수에 어떤 Side Effect Code라도 넣을 수 있다.그러면 그 코드는 지정한 의존성 배열 내 값이 변경된 경우에만 실행되며 컴포넌트가 다시 랜더링 될 때는 실행되지 않는다.
예제1.
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState(false);
//UseEffect는 모든 컴포넌트가 평가가 끝난 뒤에 (또는 재평가 뒤에) 실행된다.
// Date를 가져오는 행위는 Side Effect이다.
// 물론 데이터를 가져온 후 화면을 랜더하기에 결과는 UI와 관련이 있겠지만
// 데이터에 접근한다는 것은 UI와 관련 없는 Side Effect이기 떄문에 useEffect로 관리해야 한다.
useEffect(()=>{
const storedUserLoggedInInfomation = localStorage.getItem('isLoggedIn');
// storedUserLoggedInInfomation가 true라면(저장되어 있다면) setIsLoggedIn을 true로 설정한다.
// 그리고 state 설정 함수를 호출할 때마다 App Component는 다시 실행된다.
// App component가 다시 실행되면서 if문이 재실행된다.
if(storedUserLoggedInInfomation === '1'){
setIsLoggedIn(true);
}
// 의존성이 변경될때마다 useEffect가 실행된다.
// 앱을 처음 시작할 때에는 의존성이 변경된 것으로 간주된다.
// 이후에는 의존성 배열 내 값이 변경되지 않기에 (변경될 것이 없기 때문에) 실행되지 않는다.
},[])
const loginHandler = (email, password) => {
localStorage.setItem('isLoggedIn','1');
setIsLoggedIn(true);
};
const logoutHandler = () => {
setIsLoggedIn(false);
};
return (
<React.Fragment>
<MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</React.Fragment>
);
}
export default App;