Notice
Recent Posts
Recent Comments
Link
JiSoo's Devlog
[Udemy React 완벽 가이드] Section 13 본문
데이터베이스에 연결하지 않는 방법
- 리액트 앱이나 일반적인 브라우저 앱에서는 브라우저에서 실행되는 자바스크립트 코드가 데이터베이스와 직접 통신하면 절대 안 된다
- 데이터베이스를 데이터베이스 서버에서 실행하는 것은 문제가 안되지만 앱으로 직접 데이터를 가져오거나 저장하고 연결을 맺는 행위는 외부 환경에서 절대 해서는 안 되는 일이다
- 데이터베이스에 직접 접근하는 것은 성능 문제와 같은 다른 문제를 발생시킬 수 있지만 그 무엇보다 보안 이슈 사항이 가장 큰 문제이다
- 리액트 앱은 일반적으로 해당 백엔드 서버, 또는 백엔드 API라고 불리는 서로 다른 URL로의 요청을 전송하는 서버와 통신하게 된다
GET 요청 보내기
- 자바스크립트 내에서 HTTP 요청을 전송하는 내장 메커니즘이 있는데 Fetch API라고 한다
- Fetch API는 브라우저 내장형이며 데이터를 불러오고 이름과도 다르게 데이터 전송도 가능하다
- fetch 함수는 프로미스라는 객체를 반환하는데 이 객체는 우리가 잠재적으로 발생할 수 있는 오류나 호출에 대한 응답에 반응할 수 있는 오류나 호출에 대한 응답에 반응할 수 있게 해준다
- HTTP 요청 전송은 비동기 작업이라 즉각 끝나는 게 아닌 밀리초, 또는 몇 초가 걸리는 작업이라 당연히 실패할 가능성도 있다
- 최종 함수에 then()을 추가하면 최종 함수는 응답을 받을 때 호출된다
function fetchMoviesHandler() {
fetch("https://swapi.dev/api/films/")
.then((response) => {
return response.json();
})
.then((data) => {
const transformedMovies = data.results.map((movieData) => {
return {
id: movieData.episode_id,
title: movieData.title,
openingText: movieData.opening_crawl,
releaseDate: movieData.release_date,
};
});
setMovies(transformedMovies);
});
}
비동기/대기 사용하기
- 프로미스는 리액트에 한정된 것이 아니고 자바스크립트 언어 중 하나
- 프로미스를 다룰 때 then 체인, 즉 then 호출 뒤에 then을 재차 호출할 수 있지만 async와 await이라는 다른 문법을 사용할 수도 있다
- 함수 앞에 async 예약어를 추가하고 프로미스를 반환하는 작업 앞에 await 예약어를 사용하는데 이것은 단순히 코드 변환이며 백그라운드에서는 then 블록을 사용한 것과 같은 일을 한다
function App() {
const [movies, setMovies] = useState([]);
async function fetchMoviesHandler() {
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);
}
로딩 및 데이터 State 처리하기
- 리액트에서 로딩을 표현하기 위해 상태 관리를 사용할 수 있다
function App() {
const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
async function fetchMoviesHandler() {
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>
{!isLoading && movies.length > 0 && <MoviesList movies={movies} />}
{!isLoading && movies.length === 0 && <p>Found no movies.</p>}
{isLoading && <p>Loading...</p>}
</section>
</React.Fragment>
);
}
HTTP 오류 처리하기
- HTTP 요청을 전송하는 경우에도 무언가 잘못된 것이 있다면 오류가 발생할 수 있다
- async await를 사용하지 않고 then 을 이용해 작업한다면 catch()를 추가해 오류를 확인해야 한다
- async await를 사용한다면 try-catch를 사용해야 한다
function App() {
const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
async function fetchMoviesHandler() {
setIsLoading(true);
setError(null);
try {
const response = await fetch("https://swapi.dev/api/films/");
if (response.ok) {
throw new Error("Something went wrong!");
}
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) {
setError(error.message);
}
setIsLoading(false);
}
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>
);
}
요청에 useEffect() 사용하기
import React, { useState, useEffect, useCallback } from "react";
import MoviesList from "./components/MoviesList";
import "./App.css";
function App() {
const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const fetchMoviesHandler = useCallback(async () => {
setIsLoading(true);
setError(null);
try {
const response = await fetch("https://swapi.dev/api/films/");
if (response.ok) {
throw new Error("Something went wrong!");
}
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) {
setError(error.message);
}
setIsLoading(false);
}, []);
useEffect(() => {
fetchMoviesHandler();
}, [fetchMoviesHandler]);
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>
);
}
export default App;
POST 요청 보내기
import React, { useState, useEffect, useCallback } from "react";
import MoviesList from "./components/MoviesList";
import AddMovie from "./components/AddMovie";
import "./App.css";
function App() {
const [movies, setMovies] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const fetchMoviesHandler = useCallback(async () => {
setIsLoading(true);
setError(null);
try {
const response = await fetch(
"https://react-http-96816-default-rtdb.firebaseio.com/movies.json"
);
if (!response.ok) {
throw new Error("Something went wrong!");
}
const data = await response.json();
const loadedMovies = [];
for (const key in data) {
loadedMovies.push({
id: key,
title: data[key].title,
openingText: data[key].openingText,
releaseDate: data[key].releaseDate,
});
}
setMovies(loadedMovies);
} catch (error) {
setError(error.message);
}
setIsLoading(false);
}, []);
useEffect(() => {
fetchMoviesHandler();
}, [fetchMoviesHandler]);
async function addMovieHandler(movie) {
const response = await fetch(
"https://react-http-96816-default-rtdb.firebaseio.com/movies.json",
{
method: "POST",
body: JSON.stringify(movie),
headers: {
"Content-Type": "application/json",
},
}
);
const data = await response.json();
console.log(data);
}
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>
<AddMovie onAddMovie={addMovieHandler} />
</section>
<section>
<button onClick={fetchMoviesHandler}>Fetch Movies</button>
</section>
<section>{content}</section>
</React.Fragment>
);
}
export default App;
728x90
'Frontend > React' 카테고리의 다른 글
[Udemy React 완벽 가이드] Section 15 (2) | 2024.01.04 |
---|---|
[Udemy React 완벽 가이드] Section 14 (1) | 2024.01.04 |
[Udemy React 완벽 가이드] Section 12 (1) | 2024.01.04 |
[Udemy React 완벽 가이드] Section 11 (1) | 2024.01.04 |
[Udemy React 완벽 가이드] Section 10 (2) | 2024.01.04 |