useEffect는 컴포넌트의 생명주기 동안 특정 작업을 수행할 수 있게 해주는 리액트 훅이다. useEffect가 나오기 전에는 클래스 컴포넌트에서 생성(componentDidMount), 업데이트(componentDidUpdate), 제거(componentWillUnmount) 메서드를 통해 생명주기 변화에 대응했었다. 현재는 useEffect를 통해 간편하게 사용할 수 있게 되었다.
useEffect
- useEffect( () => {
생성이 되었을 때 시행되는 로직
return () => {제거 되었을 때 시행되는 로직}
}, [ 변화를 관찰할 props/state ]
생성(mounting)은 컴포넌트가 처음 생성되어 DOM에 추가될 때를 의미하며, 제거(unmounting)은 컴포넌트가 DOM에서 제거될 때를 의미한다. 업데이트(updating)의 경우 컴포넌트의 상태나 속성이 변경되어 다시 렌더링 될 때를 의미하는데, useEffect에서는 의존성 배열([])안에 명시된 값이 변경될 때 해당하는 useEffect가 다시 시행된다. 의존성 배열을 적지 않으면 모든 렌더링에 useEffect가 시행되고, 의존성 배열이 비어있을 경우([]) 생성과 제거시에만 시행된다.
useEffect예제
useEffect의 생성(mounting)
import './App.css'
import { useState, useEffect } from 'react';
function App() {
const [num, setNum] = useState(0);
useEffect(() => {
console.log("컴포넌트 생성")
})
return (
<>
<button onClick={() => setNum(num => num+1)}>재렌더링</button>
</>
)
}
export default App
처음에 생성되어 DOM에 추가될 때 로직이 시행되는 것을 볼 수 있고, 이후 버튼을 클릭했을 때 재렌더링이 되면서 로직이 시행되는 것을 볼 수 있다. useEffect 사용 시에 의존성 배열을 작성하지 않았기 때문에 모든 렌더링에 useEffect가 시행되어서 "컴포넌트 생성"이라는 콘솔이 찍힌 모습을 볼 수 있다.
useEffect의 업데이트(updating)
컴포넌트의 상태나 속성이 변경되어 다시 렌더링 될 때를 의미하는데, useEffect에서는 의존성 배열에 따라서 업데이트에 차이가 있다.
- 의존성배열을 작성하지 않았을 때 : 모든 렌더링에서 useEffect 로직 시행
- 의존성배열을 빈 배열([])로 작성했을 때 : DOM에 추가될 때 한 번 시행되고 이후에 시행되지 않음
- 의존성배열 안에 명시된 값([값])이 있을 때 : 명시된 값이 변경될 때마다 useEffect 시행
import './App.css'
import { useState, useEffect } from 'react';
function App() {
const [num, setNum] = useState(0);
const [text, setText] = useState("");
useEffect(() => {
console.log("의존성배열이 없는 useEffect")
})
useEffect(() => {
console.log("의존성배열이 비어있는([]) useEffect")
},[])
useEffect(() => {
console.log("의존성배열에 num만 있는([num]) useEffect")
},[num])
return (
<>
<input value={text} onChange={(e) => setText(e.target.value)} />
<button onClick={() => setNum(num => num+1)}>재렌더링</button>
</>
)
}
export default App
처음에 생성되어 컴포넌트가 DOM에 추가되었을 때 3개의 useEffect가 전부 다 시행된다. input에 글자를 작성하면 setText에 의해 재렌더링이 발생하면서 의존성배열이 없는 useEffect만 시행된다. button을 클릭하면 setNum에 의해서 재렌더링이 발생하면서 의존성 배열이 없는 useEffect와 의존성 배열에 [num]을 명시한 useEffect가 시행된다.
useEffect의 제거(unmounting)
useEffect return 결과에 작성되어 리턴되는 함수를 clean up function이라고 한다. 컴포넌트가 제거 될 때 이 함수가 1회 시행된다. clean up function이 1회 시행된다.
import './App.css'
import { useState, useEffect } from 'react';
function App() {
const [num, setNum] = useState(0);
useEffect(() => {
console.log("컴포넌트 생성");
return () => {
console.log("컴포넌트 제거")
}
},[num])
return (
<>
<button onClick={() => setNum(num => num+1)}>재렌더링</button>
</>
)
}
export default App
버튼을 클릭해서 setNum을 통해서 재렌더링을 시행할 때 컴포넌트가 DOM이 제거되었다가 다시 생성이 되는 모습을 볼 수 있다.
useEffect 실행시점
컴포넌트 안의 로직은 렌더링이 되기 전에 실행되고, useEffect의 경우 렌더링이 다 된 이후에 시행된다. 이런 실행 시점의 차이 때문에 시간이 오래 걸리는 반복연산, 서버에서 데이터를 가져오는 작업, 타이머 등의 경우 useEffect 를 사용하여 로직을 시행한다.
import './App.css'
import { useState, useEffect } from 'react';
function App() {
console.log("컴포넌트 안 로직 1: 1");
useEffect(() => { console.log("useEffect 안의 로직 : 2"); })
console.log("컴포넌트 안 로직 2: 3");
return (
<>
{console.log("return 문 안 로직 : 4")}
</>
)
}
export default App
컴포넌트 안의 로직은 렌더링이 되기 전에 실행 된 후 컴포넌트의 return 문이 렌더링이 되고, useEffect 로직이 렌더링 된 이후에 시행된 것을 볼 수 있다.
컴포넌트가 중첩되어 있을 경우에는 안쪽 컴포넌트에서부터 전체페이지로 useEffect가 전파된다. 아래의 예시를 보면 Inner에서 Outer 그리고 App으로 useEffect가 시행되는 모습을 볼 수 있다.
import { useEffect } from 'react'
import './App.css'
const Inner = () => {
useEffect(() => {
console.log("Inner의 useEffect");
})
return (
<>
</>
);
}
const Outer = () => {
useEffect(() => {
console.log("Outer의 useEffect");
})
return (
<Inner />
)
}
function App() {
useEffect(() => {
console.log("App의 useEffect");
})
return (
<Outer />
)
}
export default App
'Frontend > React' 카테고리의 다른 글
React: Memo & useMemo & useCallback을 통한 성능개선 (0) | 2024.09.06 |
---|---|
React : Lazy import을 통한 성능 개선 (0) | 2024.09.05 |
React: useReducer에 대해서 (0) | 2024.09.05 |
React: React에서 Styled Component 사용하기 (0) | 2024.09.04 |
React : 컴포넌트 합성이란 ? (1) | 2024.08.31 |
React에서 Web Component 사용하기 (0) | 2024.08.30 |
React: portal에 대해서 (0) | 2024.08.29 |
React : useRef에 대해서 (0) | 2024.08.29 |