티스토리 뷰
2020/11/16 - [React] - [React] 08. React SPA와 Router 사용하기 01
2020/11/24 - [React] - [React] 09. Router 사용하기 02
이전에 공부했던 Router를 사용하여 뉴스 뷰어를 만들어보려고 합니다.
메뉴바에서 선택된 카테고리를 url 파라미터로 전송해 해당 카테고리별로 뉴스 데이터를 보여줄 것입니다.
src/components/NewsItem.js
// 각 뉴스의 정보를 보여주는 컴포넌트
import React from "react";
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;
src/components/NewsList.js
NewsList컴포넌트에서 API를 사용하여 뉴스 데이트를 불러올 것이기 때문에 axios 라이브러리를 설치해주어야 합니다.
newsapi.org/register를 통해 뉴스 API를 발급받을 수 있습니다.
++ axios
node.js와 브라우저를 위한 http통신 javascript 라이브러리로 axios를 사용하면 GET, PUT, POST, DELETE 등의 메서드로 API 요청을 할 수 있습니다. 아래 명령어를 사용하여 설치 할 수 있습니다.
npm install axios
// API를 요청하고 뉴스 데이터를 불러옴
// 각 뉴스의 정보를 보여주는 컴포넌트
import React, { useState, useEffect } 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 {
console.log("category : ", category);
const query = category === "all" ? "" : `&category=${category}`;
const response = await axios.get(
`https://newsapi.org/v2/top-headlines?country=kr${query}&apiKey=a0f944e0583e4ab392808ecea22709f4`
);
setArticles(response.data.articles);
} catch (e) {
console.log(e);
}
setLoading(false);
};
fetchData().then((r) => console.log("ok"));
}, [category]);
// 대기 중 상태
if (loading) {
return <NewsListBlock>대기 중…</NewsListBlock>;
}
// 값이 설정되지 않은 상태
if (!articles) {
return null;
}
// articles 값이 있다면
return (
<NewsListBlock>
{articles.map((article) => (
<NewsItem key={article.url} article={article} />
))}
</NewsListBlock>
);
};
export default NewsList;
src/components/Categories.js
++ NavLink
NavLink란, 현재 경로와 Link에서 사용하는 경로가 일치하는 경우 특정 스타일 혹은 CSS 클래스를 적용할 수 있는 컴포넌트입니다.
NavLink에서 링크가 활성화되었을 때 CSS 클래스를 적용할 때 activeClassName 값을 props로 넣어 사용합니다!
import React from "react";
import styled, { css } 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}
activeClassName="active"
exact={c.name === 'all'}
to = {c.name === 'all' ? '/' : c.name}
>
{c.text}
</Category>
))}
</CategoriesBlock>
);
};
export default Categories;
src/page/NewsPage.js
NewsPage 컴포넌트에서는 match객체를 사용해 파라미터 값을 확인합니다. 값이 존재한다면 그 값을 category 변수에 넣어주고 없다면 'all'이라는 값을 넣어줍니다. 그리고 <NewsList> 컴포넌트에 props로 category를 전달해줍니다.
import React from 'react';
import Categories from '../Componentsend/Categories';
import NewsList from '../Componentsend/NewsList';
const NewsPage = ({ match }) => {
const category = match.params.category || 'all';
return (
<>
<Categories />
<NewsList category={category} />
</>
);
};
export default NewsPage;
src/App.js
그리고 마지막으로 App 컴포넌트에 <Route>를 추가해줍니다.
path에는 / :category?를 설정해주었는데요! url에 파라미터를 사용할 때에는 : 를 변수 앞에 붙여주고 사용합니다.
변수 뒤에 붙은 ? 는 파리미터가 생략되어도 매칭이 가능하다는 의미입니다.
import { Route } from "react-router-dom";
import NewsPage from "./Page/NewsPage";
const App = () => {
return <Route path="/:category?" component={NewsPage} />;
};
export default App;
코드를 실행해보면!
http://localhost:3000/science
'REACT' 카테고리의 다른 글
[React] 13. 리덕스(Redux) 사용해서 카운터 만들기 (0) | 2020.12.04 |
---|---|
[React] 12. 리덕스(Redux) 개념 정리하기 (0) | 2020.11.30 |
[React] 10. Context API 사용해보기 (0) | 2020.11.25 |
[React] 09. Router 사용하기 02 (0) | 2020.11.24 |
[React] 08. React SPA와 Router 사용하기 01 (0) | 2020.11.16 |
- Total
- Today
- Yesterday