1-9) [리액트 기초] useEffect 사용법
import { useEffect } from 'react';
useEffect(() => {
console.log('update...');
})
useEffect(callback, [의존성 배열]);
의존성배열 : 컴포넌트의 변화를 catch 하고 싶으면 의존성 배열에 값을 매핑
여러 개의 값 변화 검사하기
useEffect의 배열 요소가 여러 개 있어도 마찬가지로 검사가 가능하다.
배열 요소 중 하나라도 변경되면 useEffect는 콜백 함수를 실행한다.
// count_app/src/component/Controller.js
const Controller = (props) => {
const { handleSetcount } = props;
return (
<div>
<button onClick={() => handleSetcount(-1)}>-1</button>
<button onClick={() => handleSetcount(-10)}>-10</button>
<button onClick={() => handleSetcount(-100)}>-100</button>
<button onClick={() => handleSetcount(100)}>+100</button>
<button onClick={() => handleSetcount(10)}>+10</button>
<button onClick={() => handleSetcount(1)}n>+1</button>
</div>
)
}
export default Controller;
// count_app/src/component/Viewer.js
const Viewer = (props) => {
const { count } = props;
return (
<div>
<div>현재 카운트 : </div>
<h1>{count}</h1>
</div>
);
};
export default Viewer;
// count_app/src/App.js
import './App.css';
import Viewer from './component/Viewer';
import Controller from './component/Controller';
import { useEffect, useState } from "react";
function App() {
const [count, setcount] = useState(0);
const [text, setText] = useState('');
const handleSetcount = (value) => {
setcount(count + value);
}
useEffect(() => {
console.log('count is changed =>', text,count);
}, [text, count]);
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<input value={text} onChange={(e) => setText(e.target.value)} />
<Viewer count={count} />
</section>
<section>
<Controller handleSetcount={handleSetcount} />
</section>
</div>
);
}
export default App;
useEffect로 라이프 사이클 제어하기
이번에는 useEffect로 컴포넌트 라이프 사이클을 어떻게 제어하는지 살펴보자
컴포넌트의 3단계 라이프 사이클 중 업데이트(update)가 발생하였을 때를 살펴보도록 하자
useEffect(() => {
console.log('count is changed =>', text,count);
}, [text, count]);
// 위 코드를 아래의 코드로 수정해보자 (useEffect 에서 배열 요소를 제거해보기)
useEffect(() => {
console.log('count is changed');
});
두 번재 요소인 의존성 배열에 아무 인자도 넣지 않으면,
useEffect는 컴포넌트를 렌더링할 때마다 콜백 함수를 실행된다,
이번에는 useEffect에서 마운트 시점은 제외하고 업데이트 시점에만 콜백 함수를 실행해보는 예시를 해보자.
즉, 새로고침 처음 화면에 생성되었을 때는 콜백 함수를 실행하지 않고, 리렌더링 될 때만 실행된다는 얘기이다.
이를 위해서는 useRef도 같이 사용해야한다.
App.js를 수정해보자
의존성 배열로 아무것도 전달하지 않으면, 콜백 함수는 마운트 시점에서도 실행되어아 한다.
하지만, didMountRef 를 판단하여 초기값을 false로 설정하였기 때문에 마운트 시점에는 호출되지 않는다.
정리하자면
useEffect에서 의존성 배열을 인수로 전달X : 마운트, 업데이트 시점 모두 콜백 함수 호출 함
useEffect에서 의존성 배열을 인수로 전달O : 마운트 시점에서 콜백 함수 호출함
// count_app/src/App.js
import './App.css';
import Viewer from './component/Viewer';
import Controller from './component/Controller';
import { useRef, useEffect, useState } from "react";
function App() {
const [count, setcount] = useState(0);
const [text, setText] = useState('');
const handleSetCount = (value) => {
setcount(count + value);
}
const didMountRef = useRef(false); // App 컴포넌트 페이지에 마운트했는지 판단하는 변수로 사용. 초기값은 false 로 설정.
useEffect(() => {
if (!didMountRef.current) { // 컴포넌트가 마운트 되었을 때만 실행되도록 설정.
didMountRef.current = true;
return ;
} else {
console.log('컴포넌트 업데이트 생명주기');
}
});
useEffect(() => {
console.log('컴포넌트 마운트 생명주기, 빈 배열 시 한번만 호출...배열에 변화를 원하는 컴포넌트를 넣으면 해당 컴포넌트가 업데이트 될 때마다 호출')
},[])
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<input value={text} onChange={(e) => setText(e.target.value)} />
<Viewer count={count} />
</section>
<section>
<Controller handleSetcount={handleSetCount} />
</section>
</div>
);
}
export default App;
컴포넌트 언마운트 제어하기
라이프 사이클의 마지막 단계인 언마운트는 컴포넌트가 페이지에서 제거될 때 발생한다.
- 클린업
리액트 컴포넌트의 언마운트 시점을 제어하기 위해서는 클린업 기능을 이해해야 한다.
클린업이란 청소라는 뜻처럼, 프로그래밍에서는 특정 함수가 실행되고 종료가 될 때, 미처 정리하지 못한 내용을 처리하는 영역으로 이해하면 될 듯 하다.
위 코드에 아래 코드를 추가해보자
useEffect(() => {
setInterval(() => {
console.log('깜빡');
}, 1000)
})
App 컴포넌트를 렌더링할 때마다 useEffect으 콜백 함수는 새로운 setInterval 함수를 만들고 새 인터벌을 생성한다는 점이다.
useEffect의 두 번째 인수로 아무것도 전달하지 않았기 때문에, 버튼을 클릭해 State 변경하였다면 새 인터벌 함수를 생성한다.
또 하나는 함수 setInterval에서 인터벌을 생성한 다음에 이를 종료하지 않았기 때문이다.
인터벌을 종료하는 clearInterval 이라는 또 다른 내장 함수를 호출하지 않으면 문자열 출력은 멈추지 않는다.
그러나 기존 인터벌을 종료하지 않았기 때문에 여러개의 인터벌이 중복으로 만들어져 출력 속도가 빨라진다.
이럴 때 요긴하게 사용하는 기능이 바로 useEffect의 클린업 이라는 기능이다.
위 코드를 한번 더 수정하자.
// count_app/src/App.js
import './App.css';
import Viewer from './component/Viewer';
import Controller from './component/Controller';
import { useRef, useEffect, useState } from "react";
function App() {
const [count, setcount] = useState(0);
const [text, setText] = useState('');
const handleSetCount = (value) => {
setcount(count + value);
}
const didMountRef = useRef(false); // App 컴포넌트 페이지에 마운트했는지 판단하는 변수로 사용. 초기값은 false 로 설정.
useEffect(() => {
if (!didMountRef.current) { // 컴포넌트가 마운트 되었을 때만 실행되도록 설정.
didMountRef.current = true;
return ;
} else {
console.log('컴포넌트 업데이트 생명주기');
}
});
useEffect(() => {
console.log('컴포넌트 마운트 생명주기, 빈 배열 시 한번만 호출...배열에 변화를 원하는 컴포넌트를 넣으면 해당 컴포넌트가 업데이트 될 때마다 호출')
},[]);
useEffect(() => {
const intervalID = setInterval(() => {
console.log('깜빡');
}, 1000)
return () => {
console.log('클린업');
clearInterval(intervalID);
}
})
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<input value={text} onChange={(e) => setText(e.target.value)} />
<Viewer count={count} />
</section>
<section>
<Controller handleSetcount={handleSetCount} />
</section>
</div>
);
}
export default App;
클린업을 이용해 컴포넌트 언마운트 제어하기
클린업 기능을 어느정도 이해가 되었다.
이를 이용하여 컴포넌트가 페이지에서 사라질 때 원하는 코드를 실행하는 컴포넌트 언마운트에 대해서 살펴보자
언마운트를 진행하려면 컴포넌트가 사라지게 하는 기능이 필요한데
현재는 하나의 화면으로 구성되어있기 때문에 추가로 렌더링 가능한 페이지를 생성하자.
// count_app/src/component/Even.js
import { useEffect } from 'react';
function Even() {
useEffect(() => { //useEffect를 호출하고 의존성 배열에 빈 배열을 전달한다.
return () => {
console.log('Even 컴포넌트 언마운트')
}
},[]);
return <div>현재 카운트는 짝수입니다</div>;
}
export default Even;
// count_app/src/App.js
import './App.css';
import Viewer from './component/Viewer';
import Controller from './component/Controller';
import { useRef, useEffect, useState } from "react";
import Even from './component/Even';
function App() {
const [count, setcount] = useState(0);
const [text, setText] = useState('');
const handleSetCount = (value) => {
setcount(count + value);
}
const didMountRef = useRef(false); // App 컴포넌트 페이지에 마운트했는지 판단하는 변수로 사용. 초기값은 false 로 설정.
useEffect(() => {
if (!didMountRef.current) { // 컴포넌트가 마운트 되었을 때만 실행되도록 설정.
didMountRef.current = true;
return ;
} else {
console.log('컴포넌트 업데이트 생명주기');
}
});
useEffect(() => {
console.log('컴포넌트 마운트 생명주기, 빈 배열 시 한번만 호출...배열에 변화를 원하는 컴포넌트를 넣으면 해당 컴포넌트가 업데이트 될 때마다 호출')
},[]);
useEffect(() => {
const intervalID = setInterval(() => {
console.log('깜빡');
}, 1000)
return () => {
console.log('클린업');
clearInterval(intervalID);
}
});
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<input value={text} onChange={(e) => setText(e.target.value)} />
<Viewer count={count} />
{count % 2 === 0 && <Even />} // 조건부 렌더링(짝수일 때만 렌더링)
</section>
<section>
<Controller handleSetcount={handleSetCount} />
</section>
</div>
);
}
export default App;
App.js 에서 조건부 렌더링으로 컴포넌트가 언마운트 되도록 처리를 하였다.
{count % 2 === 0 && <Even />} // 조건부 렌더링(짝수일 때만 렌더링)
Even 컴포넌트가 언마운트 되는 시점에 특정한 이벤트를 발생시킬 수 있게 되었다.