이번에는 Hook의 또 다른 기능중에 하나인 useEffect의 대해 알아보겠다.
useEffect는 함수형 컴포넌트에서 효과들을 실행할 때 쓰이며, 기존 클래스 컴포넌트의 라이프사이클 메서드들을 대체한다.
LifeCycle Method - componentDidMount, componentDidUpdate
메소드는 크게 두 종류로 나눠진다.
생명주기 메소드에서는 Mount라는 단어가 등장하는데, 여기서 마운트는 리액트가 컴포넌트를 실제 DOM에 삽입하는 것 이다.
여기서 라이프 사이클의 대해 얘기할려면 너무 길어지기 때문에 따로 찾아보는 것을 추천한다!
그리하여 컴포넌트가 마운트 됐을 때 (처음 나타났을 때), 언마운트 됐을 때 (사라질 때), 그리고 업데이트 될 때 (특정 props가 바뀔 때) 특정 작업을 처리하는 방법에 대해 알아보겠다.
우선 UserList의 코드를 수정해준다.
import React, { useEffect } from 'react';
function User({ user, onRemove, onToggle }) {
useEffect(() => {
console.log('컴포넌트가 화면에 나타남');
return () => {
console.log('컴포넌트가 화면에서 사라짐');
};
}, []);
return (
<div>
<b
style={{
cursor: 'pointer',
color: user.active ? 'green' : 'black'
}}
onClick={() => onToggle(user.id)}
>
{user.username}
</b>
<span>({user.email})</span>
<button onClick={() => onRemove(user.id)}>삭제</button>
</div>
);
}
function UserList({ users, onRemove, onToggle }) {
return (
<div>
{users.map(user => (
<User
user={user}
key={user.id}
onRemove={onRemove}
onToggle={onToggle}
/>
))}
</div>
);
}
export default UserList;
useEffect를 사용할 때, 첫 번째 파라미터에는 함수, 두 번째 파라미터에서는 의존값이 들어있는 배열을 넣는다. 만약 두 번째 파라미터를 비우면, 컴포넌트가 처음 등장할때만 useEffect에 등록한 함수가 호출된다.
그리고 재미있는 사실은 useEffect에서는 함수를 반환 할 수 있는데 이를 cleanup 함수라고 부른다.
cleanup 함수는 useEffect의 뒷정리를 해주는 역할을한다.
두 번째 파라미터 (dependency)가 비어있는 경우에 컴포넌트가 사라질 때 cleanup 함수가 호출된다.
화면을 확인하면...
코드를 작성하고 콘솔을 확인해보니, 새로운 항목을 추가해보고 제거도 해봤다.
컴포넌트가 마운트, 언마운트 될 때 주로 우리가 추가하는 작업
마운트 될 때
언마운트 될 때
이번에는 deps에 특정 값을 넣어보겠다. deps에 특정 값을 넣게 된다면,
컴포넌트가 처음 마운트 될 때 호출되고, 지정한 값이 바뀔 때도 호출이 된다.
그리고, deps 안에 특정 값이 있다면 언마운트시에도 호출이되고, 값이 바뀌기 직전에도 호출된다.
다음과 같이 코드를 수정해보겠다.
import React, { useEffect } from 'react';
function User({ user, onRemove, onToggle }) {
useEffect(() => {
console.log('user 값이 설정됨');
console.log(user);
return () => {
console.log('user 가 바뀌기 전..');
console.log(user);
};
}, [user]);
return (
<div>
<b
style={{
cursor: 'pointer',
color: user.active ? 'green' : 'black'
}}
onClick={() => onToggle(user.id)}
>
{user.username}
</b>
<span>({user.email})</span>
<button onClick={() => onRemove(user.id)}>삭제</button>
</div>
);
}
function UserList({ users, onRemove, onToggle }) {
return (
<div>
{users.map(user => (
<User
user={user}
key={user.id}
onRemove={onRemove}
onToggle={onToggle}
/>
))}
</div>
);
}
export default UserList;
새로운 항목을 추가하고 삭제를 해보니 위에처럼 콘솔이 출력되었다.
아 참고로!
useEffect 안에서 사용하는 props, 상태가 있다면, deps에 넣어주어야 한다. 이 것은 규칙이다!
위의 코드에서는 user라는 파라미터가 사용되었기 때문에 배열에 user를 넣어준다.
그리고 만약에 useEffect 안에서 사용하는 props이나 상태를 deps에 넣지 않게 되면은, useEffect 에 등록한 함수가 실행 될 때 최신 props 혹은 상태를 가르키지 않게 된다.
deps 파라미터를 생략한다면, 컴포넌트가 리렌더링 될 때마다 호출이된다.
밑에 있는 코드를 이용해서 확인해보자!
import React, { useEffect } from 'react';
function User({ user, onRemove, onToggle }) {
useEffect(() => {
console.log(user);
});
return (
<div>
<b
style={{
cursor: 'pointer',
color: user.active ? 'green' : 'black'
}}
onClick={() => onToggle(user.id)}
>
{user.username}
</b>
<span>({user.email})</span>
<button onClick={() => onRemove(user.id)}>삭제</button>
</div>
);
}
function UserList({ users, onRemove, onToggle }) {
return (
<div>
{users.map(user => (
<User
user={user}
key={user.id}
onRemove={onRemove}
onToggle={onToggle}
/>
))}
</div>
);
}
export default UserList;
아까처럼 똑같이 먼저 등록하고 삭제해봤는데, 모든 항목들이 렌더링될 때마다 다같이 호출된다.
참고 : 벨로퍼트와 함께하는 모던 리액트
느낀점 :