비동기 작업의 이해
- 웹 애플리케이션을 만들다 보면 처리할 때 시간이 걸리는 작업이 있습니다.
- 예를 들어 웹 애플리케이션에서 서버 쪽 데이터가 필요할 때는 Ajax 기법을 사용하여 서버의 API를 호출함으로써 데이터를 수신합니다.
- 이렇게 서버의 API를 사용해야 할 때는 네트워크 송수신 과정에서 시간이 걸리기 때문에 작업이 즉시 처리되는 것이 아니라, 응답을 받을 때까지 기다렸다가 전달받은 응답 데이터를 처리합니다.
- 이 과정에서 해당 작업을 비동기적으로 처리하게 됩니다.
- 비동기적 처리
- 요청을 처리하더라도 웹 애플리케이션이 멈추지 않고 동시에 여러 가지 요청을 처리 가능
- 기다리는 과정에서 여러 함수도 호출 가능
- 서버 요청외에 특정 작업을 예약할 때
- 동기적 처리
- 한 요청이 끝날 때까지 기다리는 동안 중지 상태가 되어 다른 작업을 할 수 없다.
- 이 요청이 끝나야 다음 작업을 할 수 있음.
콜백함수
- 이렇게 서버 API를 호출할 때 외에도 작업을 비동기적으로 처리할 때가 있는데, 바로 setTimeout 함수를 사용하여 특정 작업을 예약할 때입니다.
function printMe() {
console.log('Hello World!');
}
setTimeout(printMe, 3000);
console.log('대기 중...');
//대기 중...
//Hello World!
- setTimeout이 사용되는 시점에서 코드가 3초 동안 멈추는 것이 아니라, 일단 코드가 위부터 아래까지 다 호출되고 3초 뒤에 우리가 지정해 준 printMe가 호출되고 있죠.
- 자바스크립트에서 비동기 작업을 할 때 가장 흔히 사용하는 방법은 콜백 함수를 사용하는 것입니다.
- 위 코드에서는 printMe가 3초 뒤에 호출되도록 printMe 함수 자체를 setTimeout 함수의 인자로 전달해 주었는데, 이런 함수를 콜백 함수라고 부릅니다.
function increase(number, callback){
setTimeout(() => {
const result = number + 10;
if(callback){
callback(result);
}
}, 1000)
}
increase(0, result => {
console.log(result)
increase(result, result => {
console.log(result)
increase(result, result => {
...
})
})
})
- 파라미터 값이 주어지면 1초 뒤에 10을 더해서 반환하는 함수가 있다.
- 단점 : 코드가 여러 번 중첩되어 콜백 지옥에 빠진다.
Promise
- 콜백 지옥에 빠지지 않게 하기 위한 방법
function increase(number){
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const result = number + 10;
if(result > 50){
const e = new Error('에러 메세지')
return reject(e)'
}
resolve(result);
}, 1000)
});
retrun promise;
}
increase(0)
.then(number => {
console.log(number);
return increase(number)
})
.then(number => {
console.log(number);
return increase(number)
})
.then(number => {
console.log(number)
return incrase(number)
})
.catch(e => {
console.log(e)
})
- 콜백함수를 감싸지 않고 then을 이용하여 다음 작업을 설정한다.
async/await
- Promise를 더욱 쉽게 사용할 수 있도록 해주는 문법
- 함수의 앞부분에 async, 해당 함수 내부에서 Promise의 앞부분에 await 키워드 사용
- Promise가 끝날 때까지 기다리고, 결과 값을 특정 변수에 담을 수 있다.
function increase(number){
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const result = number + 10;
if(result > 50){
const e = new Error('에러 메세지')
return reject(e)'
}
resolve(result);
}, 1000)
});
retrun promise;
}
async function runTasks() {
try{
let result = await incrase(0);
console.log(result)
result = await increase(result);
console.log(result)
result = await increase(result);
console.log(result)
}catch(e){
console.log(e)
}
}
- 예외 처리를 try, catch를 이용해서 처리
- axios와 같이 Promise 기반으로 처리되는 것이 있다면 그냥 async, await를 사용하면 됨.
axios로 API 호출해서 데이터 받아 오기
- 현재 가장 많이 사용되고 있는 자바스크립트 HTTP 클라이언트.
- HTTP 요청을 Promise 기반으로 처리한다 -> 바로 async, await 사용 가능
- 설치
- yarn add axios
- 사용
- axios.get 함수 : 파라미터로 전달된 주소에 GET요청.
- .then을 이용하여 결과값 response.data를 setData를 통해 설정.
- const [data, setData] = useState(null); const onClick= () => { axios.get('<https://jsonplaceholder.typicode.com/todos/1>').then(resoponse=>{ setData(response.data); }) }
- async, await 사용
const [data, setData] = useState(null);
const onClick = async () => {
try{
const response = await axios.get(
'<https://jsonplaceholder.typicode.com/todos/1>',
);
setData(response.data);
}catch(e){
console.log(e)
}
}
newsapi API 키 발급받기
- newsapi에서 제공하는 API를 사용하기 위해 키 발급
- https://newsapi.org/register
- 발급받은 API 키는 API를 요청할 때 쿼리 파라미터로 넣어서 사용하면 된다.
- 사용할 API : https://newspai.org/s/south-korea-news-api
- 전체 뉴스(all)과 특정 카테고리 뉴스 2가지 사용
- 클릭하면 row 데이터 생성하는 코드
const onClick = async () => {
try {
const response = await axios.get(
`http://newsapi.org/v2/top-headlines?country=kr&apiKey=74e7b5b66333419989303e6f693d732e`,
);
setData(response.data);
} catch (e) {
console.log(e);
}
};
뉴스 뷰어 UI 만들기
- 스타일드컴포넌트를 설치한다.
- 뉴스데이터에는 아래 데이터들이 있다.
- title: 제목
- description: 내용
- url: 링크
- urlToImage: 뉴스 이미지
- NewsItem에 넘겨줄 props 설정 (title, description, url, urlToImage)
- 지금은 아직 데이터를 불러오지 않고 있으니
- sampleArticle이라는 객체에 미리 예시 데이터를 넣은 후 각 컴포넌트에 전달하여 가짜 내용이 보이게 해 보세요.
const sampleArticle = {
title: '제목',
description: '내용',
url: '<https://google.com>',
urlToImage: '<https://via.placeholder.com/160>',
};
const NewsList = () => {
return (
)
데이터 연동하기
- useEffect를 사용하여 컴포넌트가 처음 렌더링되는 시점에 API를 요청하면 됩니다.
- 주의할 점은 useEffect에 등록하는 함수에 async를 붙이면 안 된다는 것
- useEffect 내부에서 async/await를 사용하고 싶다면, 함수 내부에 async 키워드가 붙은 또 다른 함수를 만들어서 사용해 주어야 합니다.
- 요청이 대기 중일 때는 loading 값이 true가 되고, 요청이 끝나면 loading 값이 false가 되어야 합니다.
카테고리 지정하기
const NewsList = ( {category} ) => {
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const query = category === 'all' ? '' : `&category=${category}`
const response = await axios.get(
`http://newsapi.org/v2/top-headlines?country=kr${query}&apiKey=74e7b5b66333419989303e6f693d732e`,
);
setArticles(response.data.articles);
} catch (e) {
console.log(e);
}
setLoading(false);
};
fetchData();
}, [category]);
}
- query 변수를 통해 카테고리 별 API 호출
- useEffect의 두 번째 파라미터에 category 설정
- App에서 category 상태를 useState로 관리하겠습니다.
- 추가로 category 값을 업데이트하는 onSelect라는 함수도 만들어 주겠습니다. 그러고 나서
- category와 onSelect 함수를 Categories 컴포넌트에게 props로 전달해 주세요.
- 또한, category 값을 NewsList 컴포넌트에게도 전달해 주어야 합니다.
- Categories에서는 props로 전달받은 onSelect를 각 Category 컴포넌트의 onClick으로 설정해 주고,
- 현재 선택된 카테고리 값에 따라 다른 스타일을 적용시켜 보세요.
- 현재 category 값이 무엇인지에 따라 요청할 주소가 동적으로 바뀌고 있습니다.
- category 값이 all이라면 query 값을 공백으로 설정하고, all이 아니라면 "&category=카테고리" 형태의 문자열을 만들도록 했습니다.
- 그리고 이 query를 요청할 때 주소에 포함시켜 주었습니다.
- 추가로 category 값이 바뀔 때마다 뉴스를 새로 불러와야 하기 때문에 useEffect의 의존 배열(두 번째 파라미터로 설정하는 배열)에 category를 넣어 주어야 합니다.
NavLink 사용하기
- 선택된 카테고리에 다른 스타일을 주는 기능
<CategoriesBlock
key = {c.name}
activeClassName="active"
exact={c.name==='all'}
to={c.name === 'all' ? '/' : `/${c.name}`}
/>
'react를 다루는 기술' 카테고리의 다른 글
16. 리덕스 라이브러리 이해하기 (0) | 2022.06.18 |
---|---|
15. Context API (0) | 2022.06.17 |
13. 리액트 라우터로 SPA 개발하기 (0) | 2022.06.15 |
12. immer를 사용하여 더 쉽게 불변성 유지하기 (0) | 2022.06.14 |
11. 컴포넌트 성능 최적화 (0) | 2022.06.13 |