웹어플리케션을 만들다보면 비동기작접으로 처리해야할때가 필요하다
한가지일만하는것이아닌 여러 작업을 실행하는, 파일 다운로드 기능이라 보면된다
이렇게 서버 API를 호출할때 외에도 작업을 비동기적으로 처리할때가있는데
바로 setTimeout 함수를 사용하여 특정작업을 예약할때이다.
function printMe() {
console.log("hello world!");
}
setTimeout(printMe, 3000);
console.log("대기중 ...");
비동기작업을 할때 가장 흔히사용하는 방법은 콜백함수를 사용하는 것이다.
1. 콜백함수
function increase(number, callback) {
setTimeout(() => {
const result = number + 10;
if (callback) {
callback(result);
}
}, 1000);
}
increase(0, (result) => {
console.log(result);
});
2. Promise
promise는 콜백 지옥같은 코드가 생기지않게 도입된기능이다.
여러 작업을 연달아 처리한다고 해서 함수를 여러번감싸는게아니라 then을
사용해서 그다음작업을 설정한다.
import { Component } from 'react';
class Counter extends Component {
state = {
number: 0,
fixedNumber: 0,
};
render() {
const { number, fixedNumber } = this.state; // state를 조회할때는 this.state로 조회한다
return (
<div>
<h1>{number}</h1>
<h2>바뀌지않는값 {fixedNumber}</h2>
<button
//onClick을 통해 버튼이 클릭되었을 때 호출할 함수를 지정합니다.
onClick={() => {
this.setState((prevState) => {
return { number: prevState.number + 1 };
}); //변하는값만 설정
this.setState((prevState) => ({ number: prevState.number + 1 }));
}}
>
+1
</button>
</div>
);
}
}
export default Counter;
function increase(number) {
const promise = new Promise((resolve, reject) => {
//resoleve는 성공, reject는 실패
setTimeout(() => {
const result = number + 10;
if (result > 50) {
const e = new Error('numbertobig');
return reject(e);
}
resolve(result);
}, 1000);
});
return 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 increase(number);
})
.then((number) => {
console.log(number);
return increase(number);
})
.then((number) => {
console.log(number);
return increase(number);
})
.catch((e) => {
//도중에 에러가 발생한다면
console.log(e);
});
3. async / await
async/await는 Promise를 더욱 쉽게 사용할수있도록 해주는 ES8문법이다.
이문법을 사용하려면 함수의 앞부분에 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('numberToobig');
return reject(e);
}
resolve(result);
}, 1000);
});
return promise;
}
async function runTasks() {
try {
let result = await increase(0);
console.log(result);
result = await increase(0);
console.log(result);
result = await increase(result);
console.log(result);
result = await increase(result);
console.log(result);
result = await increase(result);
console.log(result);
result = await increase(result);
console.log(result);
} catch (e) {
console.log(e);
}
}
4. axios로 API호출해서 데이터 받아오기
axios는 http요청을 promise 기반으로 처리한다
import { useState } from 'react';
import axios from 'axios';
const App = () => {
const [data, setData] = useState(null);
const onClick = () => {
axios
.get('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => {
setData(response.data);
});
};
return (
<div>
<div>
<button onClick={onClick}>불러오기</button>
</div>
{data && (
<textarea
rows={7}
value={JSON.stringify(data, null, 2)}
readOnly={true}
/>
)}
</div>
);
};
export default App;
그렇다면 만약 async를 적용하면 어떨까??
import { useState } from 'react';
import axios from 'axios';
const App = () => {
const [data, setData] = useState(null);
const onClick = async () => {
try {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/posts/1',
);
setData(response.data);
} catch (e) {
console.log(e);
}
};
return (
<div>
<div>
<button onClick={onClick}>불러오기</button>
</div>
{data && (
<textarea
rows={7}
value={JSON.stringify(data, null, 2)}
readOnly={true}
/>
)}
</div>
);
};
export default App;
이렇게 async () => { } 와 같은 형식으로 적용한다.
5. newsAPI 만들기
그렇다면 큰틀로 newsAPI를 만들어보자
newsapi에서 API키를 발급받아야한다.
에서 회원가입후 api키를 받는다.
https://newsapi.org/s/south-korea-news-api
에 들어가서 두가지 API 주소를 가져올것이다.
1. 전체뉴스불러오기
https://newsapi.org/v2/top-headlines?country=kr&apiKey=발급받은 api 키
https://newsapi.org/v2/top-headlines?country=kr&category=sports&apiKey=발그받은 api 키
그후 주소만 기존소스에서 바꿔준다.
import { useState } from 'react';
import axios from 'axios';
const App = () => {
const [data, setData] = useState(null);
const onClick = async () => {
try {
const response = await axios.get(
'https://newsapi.org/v2/top-headlines?country=kr&apiKey=발급받은 api키를 입력해라',
);
setData(response.data);
} catch (e) {
console.log(e);
}
};
return (
<div>
<div>
<button onClick={onClick}>불러오기</button>
</div>
{data && (
<textarea
rows={7}
value={JSON.stringify(data, null, 2)}
readOnly={true}
/>
)}
</div>
);
};
export default App;
1. 뉴스 뷰어UI 만들기
yarn add styled-components
명령어로 styled component를 설치한다.
우선 NewsItem 파일로
json 데이타의 키값인
title, description, url, urlToImage
를 보여준다.
import styled from 'styled-components';
const NewsItemBlock = styled.div`
display: flex;
.thumbnail {
margin-right: 1rem;
img {
display: block;
width: 160px;
height: 100px;
object-fit: cover;
}
}
.contents {
h2 {
margin: 0;
a {
color: black;
}
}
p {
margin: 0;
line-height: 1.5;
margin-top: 0.5rem;
white-space: normal;
}
}
& + & {
margin-top: 3rem;
}
`;
const NewsItem = ({ article }) => {
const { title, description, url, urlToImage } = article;
return (
<NewsItemBlock>
{urlToImage && (
<div className="thumbnail">
<a href={url} target="_blank" rel="noopener noreferrer">
<img src={urlToImage} alt="thumbnail" />
</a>
</div>
)}
<div className="contents">
<h2>
<a href={url} target="_blank" rel="noopener noreferrer">
{title}
</a>
</h2>
<p>{description}</p>
</div>
</NewsItemBlock>
);
};
export default NewsItem;
NewsList 파일로 보여준다
json 데이타를 자식컴포넌트에 보여줄값들을 임의로 만들어준다. (임시)
import React from 'react';
import NewItem from './NewsItem';
import styled from 'styled-components';
const NewsListBock = styled.div`
box-sizing: border-box;
padding-bottom: 3rem;
width: 768px;
margin: 0 auto;
margin-top: 2rem;
@media screen and (max-width: 768px) {
width: 100%;
padding-left: 1rem;
padding-right: 1rem;
}
`;
const sampleArticle = {
title: '제목',
description: '내용',
url: 'https://google.com',
urlToImage: 'Https://via.placeholder.com/160',
};
const NewsList = () => {
return (
<NewsListBock>
<NewItem article={sampleArticle}></NewItem>
<NewItem article={sampleArticle}></NewItem>
<NewItem article={sampleArticle}></NewItem>
<NewItem article={sampleArticle}></NewItem>
<NewItem article={sampleArticle}></NewItem>
</NewsListBock>
);
};
export default NewsList;
그후 App 폴더에서 NewsList 컴포넌트를 렌더링해준다.
import { useState } from 'react';
import axios from 'axios';
import NewsList from './Components/NewsList';
const App = () => {
return (
<div>
<NewsList></NewsList>
</div>
);
};
export default App;
그러면 인위적인 List가 보일것이다.
이인위적인 데이타를 이제 API를 사용해서 데이터를 연동해보겠다
NewsList.js 소스에 axios 를 더해준다
import React, { useEffect, useState } from 'react';
import NewItem from './NewsItem';
import styled from 'styled-components';
import axios from 'axios';
const NewsListBock = styled.div`
box-sizing: border-box;
padding-bottom: 3rem;
width: 768px;
margin: 0 auto;
margin-top: 2rem;
@media screen and (max-width: 768px) {
width: 100%;
padding-left: 1rem;
padding-right: 1rem;a
}
`;
const sampleArticle = {
title: '제목',
description: '내용',
url: 'https://google.com',
urlToImage: 'Https://via.placeholder.com/160',
};
const NewsList = () => {
const [articles, setArticles] = useState(null);
const [loading, setLoding] = useState(false);
useEffect(() => {
//async를 사용하는 함수 따로 선언
const fetchData = async () => {
try {
const response = await axios.get(
'https://newsapi.org/v2/top-headlines?country=kr&apiKey=발급받은 api키',
);
setArticles(response.data.articles);
} catch (e) {
console.log(e);
}
setLoding(false);
};
fetchData();
}, []);
if (loading) {
return <NewsListBock>대기중 ...</NewsListBock>;
}
if (!articles) {
return null;
}
return (
<NewsListBock>
{articles.map((article) => (
<NewItem key={article.url} article={article} />
))}
</NewsListBock>
);
};
export default NewsList;
여기서 중요한점은 map 함수를 조회하기전에 !articles를 조회해서 해당값이 null인지
검사해야한다. 이작업을 않한다면 데이터가없을때 null에 map 함수가 없기때문에 렌더링 과정에서 오류가 발생한다.
다음엔 카테고리 기능구현을...진행
'Book' 카테고리의 다른 글
[리액트를 다루는 기술] 8. 컴포넌트 스타일링 (0) | 2022.07.03 |
---|---|
[리액트를 다루는 기술] 7. 컴포넌트의 반복 (0) | 2022.07.03 |
[리액트를 다루는 기술] 6. ref: DOM에 이름달기 (0) | 2022.07.03 |
[리액트를 다루는 기술] 5. 이벤트 핸들링 (0) | 2022.07.02 |
[리액트를 다루는 기술] 4. 컴포넌트 (0) | 2022.06.27 |