티스토리 뷰
이 포스팅은 https://nomadcoders.co/react-for-beginners강의를 보며 작성하였습니다.(무료!)
이번 강의를 학습하기 전에 왜 이러한 것들이 필요한지 먼저 알아보도록 하자. 먼저 앞선 강의에서 배웠던 것을 활용해 똑같이 count를 세는 state를 만들어 보자.
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를 state로 선언해 주고 onClick 함수를 만들어 counter의 수가 1씩 증가하도록 만들었다. 그리고 h1에서는 변화된 counter를 보여주며, 버튼을 하나 만들어 onClick event를 통해 클릭할 시 미리 만들어둔 함수를 연결하여 setValue를 통하여 counter를 증가시켜 주었다.
잘 작동한다. 하지만 이러한 변화를 가져다주는 이유는 무엇일까? console.log를 통해 출력해 보면, 처음 페이지를 불러올 때 랜더링이 일어나고 클릭할 때마다 추가적으로 랜더링이 일어난다.
이러한 랜더링은 state값이 변화할 때 모든 함수들이 재 실행되기 때문이다. 보통은 이런 랜더링이 문제가 되지 않을 것이다. 하지만, 만약 API의 호출이 있는 함수일 경우는 어떨까?
처음의 페이지가 불러올 때 API를 요청하여 View를 보여주는 것은 아주 좋다. 하지만, 클릭을 할 때마다 API요청을 보내게 된다면 성능적으로 문제가 될 수 있을 것이다. 때문에 이러한 함수들이 있다면 페이지를 불러오는 처음 화면 한 번만 실행되게 제한하는 것이 이상적일 수 있다. useEffect를 통해 이러한 문제를 해결할 수 있다.
useEffect는 두 개의 argument를 가지는 function이다. 여기서 첫 번째 argument가 우리가 딱 한 번만 실행하고 싶은 코드이다. 두 번째 argument는 뒤에 설명할 것이다.
다시 항상 실행되는 구문을 만들고 한 번만 실행하고 싶은 함수도 만들어서 비교를 해보자.
import { useState } 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;
console.log를 통해 "I run all the time"구문은 이 전과 똑같이 랜더링이 일어날 때마다 계속 작동할 것이다. 하지만 useEffect로 실행한 iRunOnlOnce의 함수를 보자.
처음 화면에서는 두 함수가 잘 불러와진 것을 볼 수 있다.
하지만, 버튼을 클릭할 때에는 "I run all the time"구문만 출력되는 것을 확인할 수 있다. iRunOnlOnce함수는 더 이상 실행되지 않는다. 구문을 조금 더 간결하게 다음과 같이 정리할 수 있다.
const iRunOnlyOnce = () => {
console.log("I run only once.")
}
useEffect(iRunOnlyOnce, []);
useEffect(()=>{console.log("CALL THE API...")}, []);
함수를 따로 생성하지 않고 useEffect 안에 => 함수를 이용해 구문을 적었다. 똑같이 작동하며 "CALL THE API"는 한 번만 작동하는 것을 확인할 수 있다.
여기에 input tag를 이용해 검색창을 하나 만들어 보자. 먼저 state로 선언해 주고 함수를 연결해 입력창의 상태가 변화하면 그 값들을 가져온다.
import { useEffect, useState } from "react";
function App() {
const [counter, setValue] = useState(0);
const [keyword, setKeyword] = useState("");
const onChange = (event)=> {setKeyword(event.target.value)};
const onClick = ()=> setValue((prev)=>prev+1);
console.log("I run all the time");
useEffect(()=>{console.log("CALL THE API...")}, []);
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;
하지만 이렇게 state값을 넣어 주면 input값이 변화할 때마다 console.log가 찍히게 된다.
여기서 문제점은 input값을 줄 때와 버튼을 클릭할 때 모두 state의 값이 변화하게 되고 두 가지의 경우가 모두 리랜더링이 되어 console.log를 동작시켜 버린다. 그래서 이러한 코드에서 특정한 부분만이 변화했을 때 원하는 코드들을 실행할 수 있는 방법이 필요하다.
우선 useEffectf를 사용해 똑같이 처음 한 번만 랜더링 되게 만들어 준다. 그리고 두 번째 argument에 변화하는 값인 keyword를 입력해 준다.
useEffect(()=>{console.log("SEARCH FOR", keyword)},[keyword]);
하지만 입력값이 아무것도 없다면 검색할 필요가 없기 때문에 다음과 같은 조건도 걸어준다.
useEffect(()=>{
if(keyword !== "" && keyword.length > 5){
console.log("SEARCH FOR", keyword)
}},[keyword]);
이제 react를 실행해 보면
"CALL THE API"는 처음 한 번만 작동하고, 클릭 및 input값이 바뀔 때는 "I run all the time"이 잘 작동하는 것을 볼 수 있다. 또한 input값이 5글자 이상이 넘어가면 "SEARCH FOR"함수가 작동하는 것을 볼 수 있다. 이렇게 하나의 state값이 바뀌면 모두 작동하던 함수들이 각각의 상황에 맞게 실행될 수 있게 조정할 수 있다. 조금 더 심플한 예시로 변경시켜 준다면
useEffect(()=>{console.log("I run only once.")}, []);
useEffect(()=>{console.log("I run when 'keyword' changes.")},[keyword]);
useEffect(()=>{console.log("I run when 'counter' changes.")},[counter]);
처음 한번, input값이 변경될 때, 버튼을 눌렀을 때 각각 함수들을 실행할 수 있도록 분리할 수 있다.
git : https://github.com/leesulgi66/React_for_Beginners/commit/01ad829577be87de8de80179cad2b773bea13a84
정리해 보면 Effect는 두 개의 argument를 가지고 첫 번째는 우리가 실행시키고 싶은 코드를 받고, 두 번째는 dependencies라고 불리며 react.js가 지켜봐야 할 것들이다. 그리고 그것들이 변화할 때 코드는 실행된다. 이렇게 코드를 언제 실행할지 선택권을 가질 수 있게 된다.
마지막으로 Effect의 Cleanup function이라는 것을 배워보자. (많이 쓰이지 않을 수도 있다.)
import { useEffect, useState } from "react";
function Hello() {
return <h1>Hello</h1>;
}
function App() {
const [showing, setShowing] = useState(false);
const onClick = ()=>{setShowing((pre)=>!pre)};
return (
<div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? "hide" : "show"}</button>
</div>
);
}
export default App;
간단하게 버튼을 하나 만들고 state값을 이용하여 Hello라는 h1을 보여주는 컴포넌트를 만들었다.
그리고 useEffect를 이용하여 show를 눌러 Hello가 보일 때 작동하는 함수 하나를 설정해 준다.
function Hello() {
useEffect(()=>{
console.log("Im here!")
}, []);
return <h1>Hello</h1>;
}
show 버튼을 누를 때만 아주 잘 작동한다. 이렇게 필요한 컴포넌트가 불러와질 때 실행되는 함수를 만들 수 있는데, 반대로 컴포넌트가 사라질 때도 함수를 동작시킬 수 있다. 일단 이해는 잘 가지 않지만 return 구문을 하나 추가해 준다.
function Hello() {
useEffect(()=>{
console.log("created :)");
return ()=>console.log("destroyed :("); // 함수 형태로 console.log를 return해준다.
}, []);
return <h1>Hello</h1>;
}
짜잔! 이제 컴포넌트가 사라질 때에도 함수가 작동한다. 이러한 함수를 Creanup function이라고 한다. 즉 컴포넌트가 사라질 때에도 우리는 어떠한 함수를 작동시킬 수 있다.
조금 더 구문을 정리해 보면 다음과 같다.
import { useEffect, useState } from "react";
function Hello() {
function byFn() {
console.log("Bye :(")
}
function hiFn() {
console.log("Hi :)")
return byFn;
}
useEffect(hiFn, []);
return <h1>Hello</h1>;
}
function App() {
const [showing, setShowing] = useState(false);
const onClick = ()=>{setShowing((pre)=>!pre)};
return (
<div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? "hide" : "show"}</button>
</div>
);
}
export default App;
Hellow function 안에는 두 개의 function을 가지고 있다. useEffect에 hiFn을 등록해 주면 우리는 show가 클릭될 때 hiFn이 작동하는 것을 알 수 있었다. 그리고 여기 hiFn이 다시 새로운 byeFn을 return 값으로 가지고 있게 되면 컴포넌트가 사라질 때에도 함수를 작동시킬 수 있다.
'개발일지 > React' 카테고리의 다른 글
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #7 Practice Movie App Styles (0) | 2024.08.21 |
---|---|
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #7 Practice Movie App (0) | 2024.08.20 |
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #5 Create React App (0) | 2024.08.13 |
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #4 Props (0) | 2024.08.09 |
노마드 코더 - ReactJS 로 영화 웹 서비스 만들기 #3 State (1) | 2024.08.06 |