React에서 state가 바뀌면 동시에 브라우저가 업데이트 된다. 개발자들은 이를 통해 사용자와 상호작용 하는 웹사이트를 만들 수 있다.
counter 예제처럼 버튼을 누르면 자동으로 브라우저가 업데이트 되고 증가한 counter가 화면에 표시되는 기능을 state를 이용하여 편하게(re-rendering을 일일이 해줄 필요 없이) 구현할 수 있다.
하지만 개발을 하다보면 component가 처음 render 될 때만 실행하고 이후에는 실행될 필요가 없는 구문을 작성해야 할 필요성이 있다.
즉, state가 바뀔 때에는 실행되지 않아도 되는 구문을 만들 필요가 있다.
예를들어 API call을 받아오는 경우를 생각해 보자. 사용자가 버튼을 누를 때, 타이핑 할 때 마다 API를 새로 받아오게 된다면 필요없는 로딩이 걸리게 되고 시스템의 속도가 매우 저하될 것이다.
따라서 API call을 받아오는 구문을 제일 처음에만 실행시키고 이후에는 실행시키지 않는 것이 전체적인 성능에 좋을 것이다.
React Hook 중 하나인 useEffect()를 이용하면 특정 코드를 언제 실행시킬지를 결정할 수 있다.
useState와 마찬가지로 useEffect 또한 React Hook의 한 종류이다. Reack Hook을 이용하여 함수형 component에서도 state와 effect를 이용할 수 있다.
useEffect의 기본적인 사용방법에 대해 알아보자.
import { useEffect } from "react";
function App() {
useEffect(() => {
console.log("I runned Once!!");
}, []);
return <div></div>;
}
export default App;
useEffect() 는 두개의 input 인자를 받는다. 첫번째 input은 원할 때 실행시키고 싶은 함수이다. 나는 I runned Once!! 를 출력하는 함수를 작성하였다. 두번째 인자는 함수를 실행시키는 조건이다. 특정 state가 바뀔 때는 함수를 실행시켜야 한다면 두번째 인자에 state 이름을 array를 통해 입력하면 된다.
useEffect(() => {
console.log("I runned Once!!");
}, [stateA, stateB]);
component가 처음 render 되었을 때 이외에는 함수를 호출시키고 싶지 않다면 빈 array를 입력하거나 두번 째 input을 없애면 된다.
state가 바뀔 때 함수가 실행하지 않는지 확인하기 위해서 state를 추가하였다.
import { useState, useEffect } from "react";
function App() {
const [name, setName] = useState("Not woody");
const [age, setAge] = useState(0);
const changeName = () => {
name === "woody" ? setName("Not woody") : setName("woody");
};
const changeAge = () => {
setAge(age + 1);
};
const Btn = ({ title, onClick }) => {
return <button onClick={onClick}>{title}</button>;
};
useEffect(() => {
console.log("I runned Once!!");
}, [age]);
return (
<div>
<h1>I am {name}</h1>
<h2>I am {age} years old</h2>
<Btn title="change name" onClick={changeName}></Btn>
<Btn title="change age" onClick={changeAge}></Btn>
</div>
);
}
export default App;
두개의 state인 name, age와 이를 변경하는 버튼을 만들었다. useEffect()를 이용하여 처음 component가 render 될 때와 age state가 변경될 때만 I runned Once!! 구문이 출력되도록 만들었다.
처음 render 되었을 때와 age가 변경되었을 때는 출력이 되지만 name이 변경될 때는 해당 구문이 출력되지 않는것을 확인할 수 있다.
흔히 API call에 많이 쓰인다고 하니 간단한 API를 이용하여 useEffect를 사용해 보자.
import { useState, useEffect } from "react";
function App() {
const key = "1111";
const [name, setName] = useState("Not woody");
const [age, setAge] = useState(0);
const [city, setCity] = useState("");
const [temp, setTemp] = useState(0);
const changeName = () => {
name === "woody" ? setName("Not woody") : setName("woody");
};
const changeAge = () => {
setAge(age + 1);
};
const Btn = ({ title, onClick }) => {
return <button onClick={onClick}>{title}</button>;
};
const getLocation = () => {
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
};
const successCallback = (location) => {
getWeather(location);
};
const errorCallback = (error) => {
console.log(error);
};
const getWeather = async (location) => {
const [latitude, longitude] = [location.coords.latitude, location.coords.longitude];
const url = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${key}&units=metric`;
const response = await fetch(url);
const data = await response.json();
const city = data.name;
let temp = data.main.temp;
const weatherCode = data.weather[0].icon;
if (String(temp).length > 3) temp = String(temp).substring(0, 4);
setCity(city);
setTemp(temp);
};
useEffect(() => {
getLocation();
}, [age]);
return (
<div>
<h1>You Are In {city}</h1>
<h1>Temperature : {temp}</h1>
<h1>I am {name}</h1>
<h2>I am {age} years old</h2>
<Btn title="chagne name" onClick={changeName}></Btn>
<Btn title="change age" onClick={changeAge}></Btn>
</div>
);
}
export default App;
현재 위치하고있는 도시와 온도를 가져오는 API를 사용해 보았다. 아까와 마찬가지로 age가 바뀔때는 API call을 받아오고 name이 바뀔때는 받아오지 않도록 하였다.
처음 실행되었을 때와 age가 바뀔때는 API call 이 일어나지만 name이 바뀔때는 call 이 발생하지 않는 것을 확이날 수 있다.
useEffect()의 필요성과 사용법을 공부하고 간단한 API call을 useEffect()를 사용하여 처리해 보았다. React 특성상 state를 이용하여 자동으로 브라우저를 업데이트 하기 때문에 useEffect() 처럼 원할 때 함수를 호출하는 기능이 필수적이라고 느껴진다.
간단한 예제와 달리 실제로 복잡한 application을 만들면 수많은 API call 이 존재할텐데 버튼하나 누를때마다 call을 받아오면 성능에서 큰 문제가 생길수도 있겠다 싶다.