create-react-app을 통해 프로젝트를 생성하고
useState를 작성하면 자동으로 react에 있는 useState를 import 해줍니다.
import { useState } from "react";
function App() {
const [counter, setValue] = useState(0);
const onClick = () => {
setValue((prev) => prev + 1);
};
return (
<div>
<h1>{counter}</h1>
<button onClick={onClick}>click me</button>
</div>
);
}
export default App;
counter를 만들고 버튼을 클릭하면 counter가 증가하는 로직을 작성해봅시다.
function App() {
const [counter, setValue] = useState(0);
const onClick = () => {
setValue((prev) => prev + 1);
};
console.log("render");
return (
<div>
<h1>{counter}</h1>
<button onClick={onClick}>click me</button>
</div>
);
}
중간에 컴포넌트가 렌더링될 때마다 콘솔 로그에 "render"를 출력해봅시다.
"render"는 버튼을 클릭해 counter를 증가시킬 때마다 계속 출력됩니다.
하지만 우리는 처음 렌더링했을 때 한 번만 실행하고 state가 변해도 실행되지 않게 하고 싶습니다.
예를 들면, API를 통해 데이터를 가져왔을 때 데이터가 수정되면 다시 API를 호출해서 데이터를 가져오지 않게 하고 싶습니다.
✅ useEffect
컴포넌트가 처음 렌더링될 때 딱 한 번만 실행하기 위해서 사용하는 함수
useEffect는 두 개의 인자(argument)를 가집니다.
✏️ 첫 번째 인자
딱 한 번만 실행할 코드
import { useState, useEffect } from "react";
function App() {
const [counter, setValue] = useState(0);
const onClick = () => {
setValue((prev) => prev + 1);
};
console.log("i run all the time");
const iRunOnlyOnce = () => {
console.log("i run only once");
};
useEffect(iRunOnlyOnce, []);
return (
<div>
<h1>{counter}</h1>
<button onClick={onClick}>click me</button>
</div>
);
}
export default App;
useEffect를 import하고
useEffect 안에 첫 번째 인자로 한 번만 실행할 함수를 두 번째 인자로 빈 배열을 작성해줍니다.
버튼을 클릭하면 컴포넌트가 리렌더링되고 "i run all the time"은 렌더링될 때마다 출력됩니다.
하지만 useEffect를 사용한 iRunOnlyOnce 함수는 처음 렌더링될 때만 실행되기 때문에 "i run only once"는 한번만 출력됩니다.
✏️ 화살표 함수로 축약
function App() {
const [counter, setValue] = useState(0);
const onClick = () => {
setValue((prev) => prev + 1);
};
console.log("i run all the time");
useEffect(() => {
console.log("CALL THE API...");
}, []);
return (
<div>
<h1>{counter}</h1>
<button onClick={onClick}>click me</button>
</div>
);
}
위와 같이 useEffect 안에 바로 화살표 함수를 사용하여 코드를 축약할 수 있습니다.
✏️ 두 번째 인자
dependencies, React.js가 지켜보아야 하는 것들
두 번째 인자로 작성한 것들이 변할 때 React.js가 코드를 실행시킴
import { useState, useEffect } from "react";
function App() {
const [counter, setValue] = useState(0);
const [keyword, setKeyword] = useState("");
const onClick = () => {
setValue((prev) => prev + 1);
};
const onChange = (event) => {
setKeyword(event.target.value);
};
console.log("i run all the time");
useEffect(() => {
console.log("CALL THE API...");
}, []);
console.log("SEARCH FOR", keyword);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Search here..."
/>
<h1>{counter}</h1>
<button onClick={onClick}>click me</button>
</div>
);
}
export default App;
검색을 위해 input 태그를 작성하고 value로 keyword state를 연결해줍니다.
value 값이 변경될 때마다 onChange 함수를 호출하여 keyword의 값을 event.target.value로 바꿔줍니다.
위의 결과처럼 "SEARCH FOR"가 버튼을 클릭해도 출력되는 것을 확인할 수 있습니다.
하지만 이 코드는 keyword가 변경될 때만 실행되게 하고 싶습니다.
즉, counter가 변하면 실행되지 않지만 keyword가 변했을 경우만 실행하는 것입니다.
이 때, useEffect의 두 번째 인자를 사용하면 됩니다.
useEffect(() => {
console.log("SEARCH FOR", keyword);
}, [keyword]);
위와 같이 코드를 작성하면 keyword가 변했을 경우만 실행됩니다.
첫 번째 인자를 작성했던 예제에서 빈 배열을 사용한 것은 React.js가 지켜볼 것이 없기 때문에 처음 한 번만 실행된 것입니다.
하지만 문제는 처음 시작할 때도 실행이 된다는 점입니다.
useEffect(() => {
if (keyword !== "" && keyword.length > 5) {
console.log("SEARCH FOR", keyword);
}
}, [keyword]);
이렇게 조건문을 추가하여 keyword가 조건을 만족했을 경우만 실행되게 할 수 있습니다.
// 1
useEffect(() => {
console.log("I run only once");
}, []);
// 2
useEffect(() => {
console.log("I run when 'keyword' changes");
}, [keyword]);
// 3
useEffect(() => {
console.log("I run when 'counter' changes");
}, [counter]);
위의 코드처럼 언제 코드가 실행될지 결정하는 방법을 알아봅시다.
1번의 경우는 빈 배열을 인자로 넣었기 때문에 컴포넌트 생성시 처음 한 번만 실행됩니다.
2번의 경우는 keyword가 바뀔 때마다 실행되고
3번의 경우는 counter가 바뀔 때마다 실행됩니다.
✏️ Cleanup function
component가 파괴될 때 실행하는 함수를 Cleanup function이라고 함
예를 들어, component가 없어질 때 어떤 분석 결과를 보내는 경우, event listener를 지우거나 console.log에 무언가를 보여주는 경우
import { useState, useEffect } from "react";
function Hello() {
function byeFn() {
console.log("bye :(");
}
function hiFn() {
console.log("hi :)");
return byeFn;
}
React.useEffect(hiFn, []);
return <h1>Hello</h1>;
}
function App() {
const [showing, setShowing] = React.useState(false);
const onClick = () => setShowing((prev) => !prev);
return (
<div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? "Hide" : "Show"}</button>
</div>
);
}
export default App;
React.js가 지켜볼 dependency가 없기 때문에 component가 생성될 때 한 번만 실행됩니다.
component가 파괴될 때 function을 실행하고 싶다면 hiFn의 return에 함수를 작성합니다.
위의 결과처럼 컴포넌트가 생성될 때 처음 한 번 hiFn이 실행되어 console.log에 "hi :)"가 출력되고
Hide 버튼을 통해 컴포넌트를 파괴하면 byeFn이 실행되어 console.log에 "bye :("가 출력됩니다.
✏️ 다양한 방법으로 cleanup function 사용
function Hello() {
// 1. 함수를 두 개 따로 작성해서 사용
function byeFn() {
console.log("bye :(");
}
function hiFn() {
console.log("hi :)");
return byeFn;
}
useEffect(hiFn, []);
// 2. 일반 함수 사용
useEffect(function () {
console.log("hi :)");
return function () {
console.log("bye :(");
};
}, []);
// 3. 화살표 함수 사용
useEffect(() => {
console.log("hi :)");
return () => {
console.log("bye :(");
};
}, []);
return <h1>Hello</h1>;
}
1번의 경우 함수를 따로 따로 작성하여 사용합니다.
2번의 경우는 useEffect에 바로 함수를 작성하고 return에도 바로 함수를 작성합니다.
3번의 경우는 화살표 함수를 사용하여 코드를 좀 더 축약합니다.
✅ Memo VS useEffect 비교
Memo는 props가 변경되지 않았다면 컴포넌트를 리렌더링하지 않도록 해주는 것입니다.
useEffect는 props가 변경되거나 컴포넌트의 생명주기의 처음과 마지막에 한 번 실행하는 함수입니다.
'이론 (Front-end) > React' 카테고리의 다른 글
[React] CSS 설정하기 (0) | 2023.07.14 |
---|---|
[React] create-react-app로 프로젝트 생성하기 (0) | 2023.07.14 |
[React] Props, Memo, Prop Types (0) | 2023.07.13 |
[React] select 태그를 통한 컴포넌트 제어 (0) | 2023.07.12 |
[React] input 값 사용하기 (0) | 2023.06.14 |