: 스타워즈 API를 불러와 버튼 클릭 시 리스트 출력
: 여기서 api 호출은 Get요청 방식으로 진행된다.
👾 App.js
function App() {
const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
async function fetchMoviesHandler() {
setIsLoading(true);
const response = await fetch('https://swapi.dev/api/films/');
const data = await response.json();
const transformedMovies = data.results.map((movieData) => {
return {
id: movieData.episode_id,
title: movieData.title,
openingText: movieData.opening_crawl,
releaseDate: movieData.release_date,
};
});
setMovies(transformedMovies);
setIsLoading(false);
}
return (
<React.Fragment>
<section>
<button onClick={fetchMoviesHandler}>Fetch Movies</button>
</section>
<section>
// api요청 완료 후 리스트 개수 있을 경우
{!isLoading && movies.length > 0 && <MoviesList movies={movies} />}
// api요청 완료 후 리스트 개수가 없을 경우
{!isLoading && movies.length === 0 && <p>Found no movies.</p>}
// api요청 완료 전
{isLoading && <p>Loading...</p>}
</section>
</React.Fragment>
);
}
👉🏻 로딩 결과에 따른 화면 출력을 state로 관리함.
response.ok
: 요청이 성공적인지 그렇지 않은지를 불린값으로 반환함. 이것을 사용하여 자체적인 오류를 만들어 표시하면 됨!!🚨 오류 종류
401, 403, 404응답
: 기술적으로는 성공적으로 응답을 받았으나 응답에 오류상태 코드가 포함되어 있어서 오류문자를 받아 발생5xx
: 서버에 오류가 있을 때 발생👾 App.js
function App() {
const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
// 초기에는 오류가 없기 때문에 초기값을 null로 설정
const [error, setError] = useState(null);
async function fetchMoviesHandler() {
setIsLoading(true);
// 이전에 받았던 error를 초기화
setError(null);
try {
const response = await fetch('https://swapi.dev/api/films/');
// 오류 상태코드 발생 시 오류 생성!!
if(!reponse.ok){
throw new Error('에러 발생');
}
const data = await response.json();
const transformedMovies = data.results.map((movieData) => {
return {
id: movieData.episode_id,
title: movieData.title,
openingText: movieData.opening_crawl,
releaseDate: movieData.release_date,
};
});
setMovies(transformedMovies);
} catch(error) {
// try블록에서 발생할 수 있는 잠재적인 오류들을 catch로 포착
// error state에 에러메세지 저장
setError(error.message);
}
// error가 발생했던 간에 로딩은 끝난 상태여야 함.
setIsLoading(false);
}
return (
<React.Fragment>
<section>
<button onClick={fetchMoviesHandler}>Fetch Movies</button>
</section>
<section>
{!isLoading && movies.length > 0 && <MoviesList movies={movies} />}
{!isLoading && movies.length === 0 && !error && <p>Found no movies.</p>}
// error발생 시 에러메세지 출력
{!isLoading && error && <p>{error}</p>}
{isLoading && <p>Loading...</p>}
</section>
</React.Fragment>
);
}
👾 return 리팩토링
let content = <p>Found no movies.</p>;
if(movies.length > 0){
content = <MoviesList movies={movies} />;
}
if(error){
content = <p>{error}</p>;
}
if(isLoading){
content = <p>Loading...</p>;
}
return(
<React.Fragment>
<section>
<button onClick={fetchMoviesHandler}>Fetch Movies</button>
</section>
<section>{content}</section>
</React.Fragment>
);
👉🏻 content만 비교하여 렌더링하게 됨!
👾 fetchMoviesHandler함수 리팩토링
function App() {
const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const fetchMoviesHandler = useCallback( async () => {
setIsLoading(true);
setError(null);
...
}, []);
// 이 함수는 외부 의존성이 없으므로 의존성배열을 빈값으로 둔다!
// fetchMoviesHandler는 함수이므로 app이 재평가 될때마다 메모리에 새롭게 저장됨(무한루프) -> 함수 재정의 방지를 위해 useCallback훅을 사용한다.
// app컴포넌트 재평가 시 함수의 호출을 방지하고, 필요한 경우(버튼 클릭)에만 호출하기 위함!
useEffect(() => {
fetchMoviesHandler();
},[fetchMoviesHandler]);
...
}
👉🏻 useEffect(()=>{fetchMoviesHandler();},[]);
: 의존성 배열을 빈값으로 둠으로써 최초 로딩 시 api호출, app이 재렌더링 시 재호출 되는것을 방지함. 하지만 의존성 배열에 의존성을 표시해야 좋은 코드이다.
👉🏻 fetchMoviesHandler함수 재정의 방지를 위해 useCallback훅을 사용한다.
: 사용자를 추가하는 경우 서버에 데이터를 보내는 작업을 한다.
: Firebase
는 코드 작성 없이 사용 가능한 백엔드 서비스이며, 우리의 요청을 주고 받을 수 있으며, Post 요청 작업을 수행할 수 있다.(완전한 REST API를 제공)
: fetch
: 기본적으로 Get요청을 보내지만, Post요청으로 사용하면 데이터를 전송하는데에도 사용가능함. 두번째 인자에 객체를 생성
👾 영화 추가하는 버튼 클릭 시 addMovieHandler호출하여 Firebase에 해당 영화 추가됨.
async function addMovieHandler(movie) {
const response = await fetch('https://react-http-6b4a6.firebaseio.com/movies.json', {
method: 'POST', // dafault 'GET'
body: JSON.stringify(movie), // JSON형태로 변경
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
console.log(data);
}
👉🏻 일반적으로도 그렇지만 Firebase에서 POST요청을 보내면 데이터베이스에서 리소스가 생성됨.
👉🏻 body옵션
: 저장할 리소스 작성
👉🏻 headers옵션
: 객체를 지정, Firebase는 headers가 필요없지만 요청을 받는 대다수의 api는 이러한 헤더를 필요로 함. 이 헤더를 통해 어떤 컨텐츠가 전달되는지 알 수 있음!
👉🏻 Firebase는 자동으로 컨텐츠에 아이디를 생성하고, id를 key로 갖고 추가된 영화 데이터가 객체형태로 value에 저장됨!
[참고] Udemy - React 완벽 가이드 with Redux, Next.js, TypeScript