1. 뉴스 뷰어를 빌드하기 전에 사용되는 비동기 작업과 다른 기술에 대한 정리를 해보자
서버의 API를 사용할 때 네트워크 송수신 과정에서 시간이 걸리기에 응답을 받을 때까지
기다렸다가 전달받은 응답 데이터를 처리하는 방식이 비동기 작업 방식이다.
비동기적으로 처리한다면 웹 애플리케이션이 멈추지 않고 동시에 여러 가지 작업을 진행하고,
대기 중에도 다른 함수를 호출할 수 있다.
콜백함수
사실 이 기술(콜백 함수)은 너무 많이 중첩하여 사용하게 되면 코드의 가독성이 나빠서 설명은 되도록이면 안 하겠다.....
아래의 2가지 종류는 이전에 작성했던 글을 참고하자.
2. 코드 및 설명
코드 : https://github.com/Gotkwondo/just_do_it/tree/main/ReactStudy/news-viewer
1)
우선 App.js에서 크게 어려웠던 부분은 없다. 하위 컴포넌트를 불러올 뿐 라우팅 경로 설정도 어려운 부분이 없었다.
코드 보기↓↓↓
import { Route, Routes } from 'react-router';
import NewsPage from './pages/NewsPage';
const App = () => {
return (
<>
<Routes>
<Route path="/*" element={<NewsPage />}>
<Route path=":category" element={<NewsPage />} />
</Route>
</Routes>
</>
);
};
export default App;
2)
카테고리와 뉴스를 보여주는 컴포넌트인 NewsPage.js이다.
여기에서는 useParams를 이용해 App.js에서 라우팅 경로를 받아와 객체 래핑 해서 실질적으로 뉴스 내용을 보여주는
컴포넌트인 NewsList 컴포넌트에 객체 정보를 전달했다.
코드 보기↓↓↓
import Categories from '../component/Categories';
import NewsList from '../component/NewsList';
import { useParams } from 'react-router-dom';
const NewsPage = () => {
//카테고리가 선택되지 않았으면 기본값 all로 사용
// const {category} = useParams() || "all";
const {category} = useParams();
return (
<>
<Categories />
<NewsList category={category} />
</>
);
};
export default NewsPage;
어려웠던 점은 책에서 react-router v5를 사용하여 내가 사용했던 v6에서 삭제되거나 변경된 기술들이 많이 사용돼서
동작하는 데에 어려움이 있었다. 아래의 코드에서는 useParams와 라우팅 경로를 얻어오는데에서 어려움이 있었다.
v6에서는 path=":category?"과 같이 ?를 붙여 optional path 설정이 불가능하다. 그래서 App.js에서 한 것처럼 상위
라우트와 하위 라우트를 나누어 작성해주어 문제를 해결했다. optional path 사용이 불가능하여 주석 처리된 카테고리의
기본값을 설정하는 코드는 동작하지 않으므로 다른 코드로 대체하였다.
3)
다음은 뉴스의 카테고리를 고를수 있는 Categories.js이다.
우선 카테고리에 해당하는 name과 text 값을 갖는 객체들을 배열로 선언했다.
이는 map함수를 이용하기 위함이다.
또한 css스타일은 "styled-components"를 이용했다.
카테고리를 눌렀을때 isActive여부를 판단하여 className으로 active클래스를 선언해주는 코드를 삼항연산자를 통해
작성했다. 그리고 경로 설정에서 name값이 all일 경우는 모든 분야의 뉴스를 보이게 하도록 경로를 설정했다.
코드 보기↓↓↓
import styled from 'styled-components';
import { NavLink } from 'react-router-dom';
const categories = [
{
name: 'all',
text: '전체보기'
},
{
name: 'business',
text: '비즈니스'
},
{
name: 'entertainment',
text: '엔터네인먼트'
},
{
name: 'health',
text: '건강'
},
{
name: 'science',
text: '과학'
},
{
name: 'sports',
text: '스포츠'
},
{
name: 'technology',
text: '기술'
}
];
const CategoriesBlock = styled.div`
display: flex;
padding: 1rem;
width: 768px;
margin: 0 auto;
@media screen and (max-width: 768px){
width: 100%;
overflow-x: auto;
}
`;
const Category = styled(NavLink)`
font-size: 1.125rem;
cursor: pointer;
white-space: pre;
text-decoration: none;
color: inherit;
padding-bottom: 0.25rem;
&:hover {
color: #495057;
}
&.active {
font-weight: 600;
border-bottom: 2px solid #22b8cf;
color: #22b8cf;
&:hover {
color: #3bc9db;
}
}
& + & {
margin-left: 1rem;
}
`;
const Categories = () => {
return (
<CategoriesBlock>
{categories.map(c => (
<Category
key={c.name}
className={({isActive}) => isActive ? 'active' : undefined}
to={c.name === 'all' ? '/' : `/${c.name}`}>
{c.text}
</Category>
))}
</CategoriesBlock>
);
};
export default Categories;
어려웠던 점은 여기서도 버전이 업데이트되며 나타난 어려움이다.
우선 NavLink에서 사용됬던 activeClassName과 activeStyle이 삭제되고 className과 style로 변경되었다.
사용하려면 위와같이 삼항연산자를 이용하여 설정해줘야 한다.
4)
가장 어려웠던 컴포넌트인 NewsList이다.
스타일은 styled-components를 이용했고
axios를 통해 뉴스를 직접 보여주는 API인 NewsAPI를 불러왔다.
async/await를 이용해 API 요청이 대기중인지 판별 가능하게 했고, 판별한 결과를 통해
로딩중 임을 알려주는 문자를 렌더링 해주었다.
코드 보기↓↓↓
import { useEffect, useState } from 'react';
import styled from 'styled-components';
import NewsItem from './NewsItem';
import axios from 'axios';
const NewsListBlock = 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 NewsList = ({category}) => {
const [articles, setArticles] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
//const query = (category === "") ? "" : `&category=${category}`; 이 코드는 안됨 (""과 undefined는 falsy비교에서 false이다.)
const query = (category === undefined) ? "" : `&category=${category}`;
const response = await axios.get(
`https://newsapi.org/v2/top-headlines?country=kr${query}&apiKey=c1875192f7424058b26761c4799c6517`,
);
setArticles(response.data.articles);
} catch (e) {
console.log(e);
}
setLoading(false);
};
fetchData();
}, [category]);
//대기 중일 때
if (loading) {
return <NewsListBlock>로딩중...</NewsListBlock>
}
//아직 articles 값이 설정 안됬을 때
if (!articles) {
return null;
}
return (
<NewsListBlock>
{articles.map(articles => (
<NewsItem key={articles.url} article={articles} />
))}
</NewsListBlock>
);
};
export default NewsList;
어려웠던 점이다.
여기서 시간을 굉장히 많이 썻다.
버전이 업데이트 됬다는 말은 많이했다. 그로인해 생겨난 어려움이 여기서 폭발했던것 같다.
또한 내가 아직 자바스크립트에 대해 많이 부족했다는 점을 알게되었다.
위에서 query를 선언하는 코드에서 주석처리되어있는 코드를 처음엔 사용했다.
하지만 렌더링 되지않아 다른 falsy값으로 변경했지만 렌더링되지 않았다.
처음에는 다른 컴포넌트의 문제인줄 알았지만, React 개발자 도구에서 Component를 확인해 보니
다른 falsy값이 아닌 undefined가 해당 컴포넌트에 파라미터로 받음을 알게되어 해결할 수 있었다.
4)
마지막으로 뉴스 아이템 각각의 렌더링을 담당하는 NewsItem 컴포넌트이다.
이 코드에서는 styled-components로 스타일을 설정했고, NewsList에서 API로 받아온 뉴스 객체 정보 article을
렌더링 해주었다.
코드 보기↓↓↓
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="thumnail" />
</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;
이 코드에서는 큰 어려움은 없었다.
이로써 React를 이용한 첫 사이드 프로젝트가 완성되었다. 3일에 걸려 완성시켜 조금은 힘들었다.
(오류 해결에 2일 쓴것은 안비밀....)
어려운 부분도 있었지만 진짜 구글링의 힘을 빌려 영어로된 글도 읽어가며 해결했던것 같다.
그 중 가장 도움이 많이 됬던 것은 react-router v6 에서 변경된 것을 정리한 블로그와 각 에러에 대한
토론을 한 stackoverflow 글들이 정말 고마운 존재들이였다......
'React' 카테고리의 다른 글
React) 16장 redux 라이브러리 (0) | 2022.05.12 |
---|---|
React) 15장 Context API (0) | 2022.05.11 |
React) 13장 리액트 라우터로 SPA개발하기 (0) | 2022.05.07 |
React) 12장 immer 라이브러리 (0) | 2022.05.06 |
React) 11장 컴포넌트 최적화 (0) | 2022.04.19 |