-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
news-viewer project finished. code review start #42
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,12 @@ | ||
import React, {useState} from 'react' | ||
import axios from 'axios' | ||
|
||
import React from 'react' | ||
import {Route} from 'react-router-dom' | ||
import NewsPage from './components/NewsPage' | ||
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=') | ||
setData(response.data) | ||
}catch(e){ | ||
console.log(e) | ||
} | ||
} | ||
|
||
return ( | ||
<div> | ||
<div> | ||
<button onClick={onClick}>Loading</button> | ||
</div> | ||
{data && <textarea rows={7} value={JSON.stringify(data, null, 2)} readOnly={true} />} | ||
</div> | ||
<Route path="/:category?" component={NewsPage} /> | ||
) | ||
|
||
} | ||
|
||
export default App |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import React from 'react' | ||
import styled from 'styled-components' | ||
import {NavLink} from 'react-router-dom' | ||
|
||
const categories = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NavLink (React Router) 에서 상단 네브바를 구성할 리터럴 객체 작업 |
||
{ | ||
name : "all", | ||
text : "see all" | ||
}, | ||
{ | ||
name : "business", | ||
text : "Business" | ||
}, | ||
{ | ||
name : "entertainment", | ||
text : "entertainment" | ||
}, | ||
{ | ||
name : "health", | ||
text : "health" | ||
}, | ||
{ | ||
name : "science", | ||
text : "science" | ||
}, | ||
{ | ||
name : "sports", | ||
text : "sports" | ||
}, | ||
{ | ||
name : "technology", | ||
text : "technology" | ||
} | ||
] | ||
|
||
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; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React, {useEffect, useState} from 'react' | ||
import styled from 'styled-components' | ||
import NewsItem from './NewsItem' | ||
import axios from 'axios' | ||
import usePromise from '../lib/usePromise' | ||
|
||
|
||
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 [article, setArticle] = useState(null) | ||
// const [loading, setLoading] = useState(false) | ||
// useEffect(()=>{ | ||
// const fetchData = async ()=>{ | ||
// setLoading(true) | ||
// try{ | ||
// const query = category === 'all' ? '' : `&category=${category}` | ||
// const response = await axios.get(`https://newsapi.org/v2/top-headlines?country=kr${query}&apiKey=b893fb160a4b401fb4974a5a89d42111`) | ||
// setArticle(response.data.articles) | ||
// }catch(e){ | ||
// console.log(e) | ||
// } | ||
// setLoading(false) | ||
// } | ||
// fetchData() | ||
const [loading, response, error] = usePromise(()=>{ | ||
const query = category === 'all' ? '' : `&category=${category}` | ||
return axios.get(`https://newsapi.org/v2/top-headlines?country=kr${query}&apiKey=b893fb160a4b401fb4974a5a89d42111`) | ||
}, [category]) | ||
|
||
if(loading){ | ||
return <NewsListBlock>Loading ...</NewsListBlock> | ||
} | ||
if(!response){ | ||
return null | ||
} | ||
if(error){ | ||
return <NewsListBlock>Error Occured!</NewsListBlock> | ||
} | ||
const {articles} = response.data | ||
return ( | ||
<NewsListBlock> | ||
{articles.map(article=>( | ||
<NewsItem key={article.key} article={article} /> | ||
))} | ||
</NewsListBlock> | ||
) | ||
} | ||
|
||
export default NewsList |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import React from 'react' | ||
import Categories from '../components/Categories' | ||
import NewsList from '../components/NewsList' | ||
|
||
const NewsPage = ({match}) =>{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. {match} 속성은 React-Router를 활용하면 가져오는 속성으로 url의 param을 가져온다. |
||
const category = match.params.category || 'all' | ||
return ( | ||
<> | ||
<Categories /> | ||
<NewsList category={category}/> | ||
</> | ||
) | ||
} | ||
|
||
export default NewsPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,12 @@ import ReactDOM from 'react-dom'; | |
import './index.css'; | ||
import App from './App'; | ||
import reportWebVitals from './reportWebVitals'; | ||
import {BrowserRouter} from 'react-router-dom' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. react-router-dom 설정하기 |
||
|
||
ReactDOM.render( | ||
<React.StrictMode> | ||
<BrowserRouter> | ||
<App /> | ||
</React.StrictMode>, | ||
</BrowserRouter>, | ||
document.getElementById('root') | ||
); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import {useState, useEffect} from 'react' | ||
|
||
export default function usePromise(promiseCreator, deps){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. news api 정보의 대기, 로딩 완료, 실패를 가져오게끔 별도의 컴포넌트를 구성해 작업하는 파일 |
||
// standby / completed / fail status management | ||
const [loading, setLoading] = useState(false) | ||
const [resolved, setResolved] = useState(null) | ||
const [error, setError] = useState(null) | ||
|
||
useEffect(()=>{ | ||
const process = async () =>{ | ||
setLoading(true) | ||
try{ | ||
const resolved = await promiseCreator() | ||
setResolved(resolved) | ||
}catch(e){ | ||
setError(e) | ||
} | ||
setLoading(false) | ||
} | ||
process() | ||
}, | ||
deps) | ||
return [loading, resolved, error] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컴포넌트 파일에서 만들어진 News page 값을 React-Router로 연결해 값을 받는다.