📌 지난 포스트
[React] Create-React-App (CRA)으로 리액트 프로젝트 시작하기 ①
[React] Create-React-App (CRA)으로 리액트 프로젝트 시작하기 ②
🪄 리액트에서는 상태(state)가 변경될 때마다 컴포넌트가 다시 렌더링된다. 그런데 만약 API를 통해 데이터를 가져오는 작업이 렌더링 때마다 반복된다면 비효율적일 것이다.
화면을 새로고침하면 컴포넌트가 최초로 렌더링되며 데이터를 불러온다. 그런데 딱 여기까지. 데이터 요청 등 특수한 작업은 최초 렌더링 될 때 한 번만 되길 원할 것이다.
그래서 이번 포스트에서는 최초 렌더링 시 한 번만 실행하는 방법을 배우고자 한다.
📌 create-react-app을 사용하면 React.useState() 대신 useState()만 써도 된다. 다만, 이렇게 사용하려면 react에서 useState를 미리 불러와야 한다! import {useState} from 'react'; 이렇게!
🔹 아래 코드의 경우 상태가 변경될 때 App 함수 전체 코드가 렌더링되기 때문에 console.log('I run all the time');는 여러번 실행 될 것이다. 말이 console.log이지, 다른 코드였으면 정말 비효율적이고 성능도 많이 떨어질 것이다.
<script>
import {useState} from 'react';
function App() {
const [counter, setValue] = useState(0);
const onClick = () => setValue((prev) => prev+1);
console.log('I run all the time'); // 상태 변화될 때마다 실행될 것 (비효율적!!!)
return (
<div>
<h2>Total Click : {counter}</h2>
<button onClick={onClick}>Click me!!!</button>
</div>
);
}
</script>
🔹 useEffect(실행할 함수, [의존성 배열(dependencyList)]) 처럼 두개의 인수를 받고, dependency가 존재하면 해당 배열 상태가 변경될 때마다 함수가 실행되는 것이다. 배열을 비워두면 최초 한 번만 실행된다. 이게 전부다. 진짜 쉽다.
🔹 배열을 비워두면 최초 한 번만 실행된다.
<script>
import {useState, useEffect} from 'react';
// 코드 중략...
useEffect(() => {
console.log('I run only once');
}, []);
</script>
🔹 상태 변화를 감시 받아야하는 dependency를 명시하면, 상태가 변경될 때마다 실행된다.
<script>
useEffect(() => {
console.log('SEARCH FOR', keyword);
}, [keyword]);
</script>
🔹 예시로 영화 검색 API를 활용한다고 했을 때, input 요소에 텍스트를 한글자 한글자 입력할 때마다 API를 호출한다면 정말 끔찍할 것이다. 물론 특정 값이 바뀔 때마다 실행되도록 할 수 있지만, 더 디테일한 조건부를 추가해야한다면..? 값이 바뀔 때마다 실행되긴 해야하지만, 공백이 아니어야하고, 글자 수가 5자 이상일 때의 조건을 덧붙여야 한다면..! 이렇게 if문으로 작성해볼 수 있다.
<script>
useEffect(() => {
if(keyword !== "", keyword.length > 5){
console.log('SEARCH FOR', keyword);
}
}, [keyword]);
</script>
🔹 만약 버튼 컴포넌트와 input 컴포넌트가 있다. 버튼을 클릭할 때는 input 관련 함수가 실행되어서는 안되고, 버튼 관련 함수만 실행되어야한다. input 동작때도 마찬가지. 이럴 때는 위에서 본 것처럼 dependency만 각각 설정해주면 된다.
🔹 그런데, 버튼 클릭과 input 동작 시 공통적으로 실행시키고자하는 함수가 있다면? 복잡하게 생각할 것 없이 dependenty를 나란히 적어주면 된다. [counter, keyword]처럼!!
<script>
// 1회만 최초 실행
useEffect(() => {
console.log('I run only once.');
}, []);
// counter 상태 값이 변경될 때마다 실행
useEffect(() => {
console.log('I run when "counter" changes');
}, [counter]);
// keyword 상태 값이 변경될 때마다 실행
useEffect(() => {
console.log('I run when "keyword" changes')
}, [keyword]);
// counter, keyword 상태 값이 변경될 때마다 실행
useEffect(() => {
console.log('I run when "keyword & counter" changes');
},[keyword, counter]);
</script>
🪄 useEffect 안에서 이벤트 리스너나 타이머 같은 작업을 설정했다면, 컴포넌트가 사라지거나(destroy) 다시 실행될 때(create) 이전 작업을 정리해 주어야 한다. 이때 사용하는 것이 바로 cleanup 함수이다.
🔹 cleanup 함수라고 해서 복잡하거나 어려운 문법은 절대 아니다. function에서 return의 원리만 알고 있으면 충분히 사용할 수 있다.
🔹 "특정 조건일 때 실행, 조건에서 벗어나면 종료" 이 원리를 바탕으로 useEffect 안에서는 return 뒤에 오는 함수가 cleanup 함수가 되며, 컴포넌트가 사라질 때(destroy) 호출된다.
🔹 사용방법은 다양하다. destroy 함수, create 함수를 각각 선언한 후 호출하는 방법도 있고, 화살표 함수 표기로 한 번에 작성하는 방법도 있다. 코드가 간결하다면 한 번에 작성하는게 편할텐데, 이건 정말 기초 중의 기초라 화살표 함수 표기법이 쉬워보이는 거겠지..ㅎ
<script>
// 화살표 함수 표기법
useEffect(() => {
console.log("hi");
return () => console.log('bye');
}, []);
// 함수 선언 후 실행법
function Hello(){
function byFn(){
console.log('bye :(');
}
function hiFn(){
console.log('create :)');
return byFn; //destroy될 때
}
}
</script>
🪄 지금까지의 포스트를 통해 리액트 기초를 다져보았다. 다음 포스트부터는 기초를 바탕으로 프로젝트를 시작할텐데, 당황하지 않고 천천히 차근차근 배워나가며 리액트를 부셔버리겠다...후하 아디오스!