그럼 간단하게 useEffect를 통해서 movie api를 호출한다음 title을 랜더링 해보도록 하자.
import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
function SWMovies() {
const [number, setNumber] = useState(1);
const [movie, setMovie] = useState('');
useEffect(() => {
async function getData() {
const response = await axios.get(
`https://swapi.dev/api/films/${number}/`
);
setMovie(response.data);
}
getData();
});
return (
<div>
<h1>Pick A Movie</h1>
<h4>{movie.title}</h4>
<select value={number} onChange={e => setNumber(e.target.value)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
</select>
</div>
);
}
export default SWMovies;
dropdown을 select로 구현한다음 숫자를 선택하면 그에 해당되는 스타워즈 영화의 제목이 나오도록 했다. 참고로, useEffect를 사용할때는 무언가 리턴이 되는 함수를 사용하면 안된다. 따라서 arrow 함수안에 또다시 함수를 만들어서 사용했다.
그러나 요렇게 코드짜면, 문제가 생겨버린다. 어떤 문제일까??...
바로 그 유명한 stackOverFlow가 생긴다ㅋㅋ.
setNumber가 실행되면서 랜더링되고 useEffect가 실행되면서 setMovie가 실행된다. 그럼 랜더링되면서 useEffect가 실행되면서 무한 반복이다. 따라서 number가 바뀔때만 useEffect가 한 번만 실행되도록 해야한다. 이때 useEffect의 2번째 인자에 number를 넣으면 된다.
useEffect(() => {
async function getData() {
blah
blah
}, [number]);
두번째 인자 array 안에 들어가는 값이 변하면 useEffect가 실행된다. 이렇게 useState와 연계해서 사용가능하다.
그러나, 만일 useState의 초기값에 아무것도 pass되지 않는다면, axio에서 오류가 날것이다. 이런 경우를 대비해서 초기값을 설정해주자.
또는, useRef
Hook 함수를 사용하여 에러를 방지 할 수 도 있다.
const isFirstRun = useRef(true);
useEffect(() => {
async function getData() {
if (isFirstRun.current) {
isFirstRun.current = false;
return;
}
const response = await axios.get(`https://swapi.dev/api/films/${number}/`);
setMovie(response.data);
}
getData();
}, [number]);
참고로 effect 라는 이름을 잘 생각해보자. 효과이다. 컴포넌트가 랜더링되고 난 뒤에 실행되므로 어떤 효과를 줄 수 있는 것이다. 즉, 부수효과 sideEffect를 야기할때도 useEffect를 쓴다. 데이터를 불러온다거나 이벤트를 등록할때와 같이 리액트 함수와 관련없는 일을 하고 싶을때는 useEffect안에서 실행하면 된다.
그리고 이벤트같은거 등록해주고 난뒤에는 return을 이용해서 remove해주자.