14.1 뉴스 만들기 (API, UI)

hey hey·2021년 12월 14일
0

리액트 배우기

목록 보기
20/26
post-thumbnail

비동기 작업

서버쪽 데이터를 받아올 때는 API를 호출함으로 써 데이터를 수신하는데

이 과정에서 시간이 걸리기 때문에 이 작업을 비동기적으로 처리하게 된다.

콜백함수

비동기 작업을 할 때 가장 흔히 사용하는 방법

Promise

콜백 지옥을 예방하기 위해 나온 기능

async/await

Promise를 더 쉽게 사용할 수 있도록 하는 문법

함수 앞에 async 키워드를 추가하고 Promise 앞부분에 await 를 사용

axios로 API 호출해서 데이터 받아오기

$ yarn create react-app news-viewer

$ yarn add axios

.prettierrc

코드 스타일 자동으로 정리하기

{
  "singleQuote": true,
  "semi": true,
  "useTabs": false,
  "tabWidth": 2,
  "trailingComma": "all",
  "printWidth": 80
}

jsconfig.json

파일 자동 불러오기를 잘 활용하고 싶다면

{
  "compilerOptions": {
    "target": "ES6"
  }
}

App.js

import axios from 'axios';
import {useState} from 'react'
import './App.css';

const App = () => {
  const [data,setData] = useState(null)
  const onClick= ()=>{
    axios.get('https://jsonplaceholder.typicode.com/todos/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;

const [data,setData] = useState(null)

빈 data를 만들어놓는다

onClick 하게 된다면

axios.get('https://jsonplaceholder.typicode.com/todos/1')

주소로 axios 요청을 보내 API를 호출하게 되고 ('GET')

.then(response=>{setData(response.data)})

값을 받는데 성공하면 data의 값을 response 내용으로 바꾼다 (비동기적)

{data && <textarea rows={7} value={JSON.stringify(data,null,2)} readOnly={true} />}
data 가 null이 아니면 출력을 한다.

async/await 사용하기

App.js

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

사전 API 발급받기 : https://newsapi.org/register/success

내 API 키 : 755b48e892b34cab8c2f6f7be92d8944

한국 뉴스 가져오는 API 설명서 : https://newsapi.org/s/south-korea-news-api

두가지 형태

  1. 전체 뉴스 불러오기

    https://newsapi.org/v2/top-headlines?**country=kr**&apiKey=755b48e892b34cab8c2f6f7be92d8944

  2. 특정 카테고리 불러오기

    https://newsapi.org/v2/top-headlines?**country=kr**&**category=sports**&apiKey=755b48e892b34cab8c2f6f7be92d8944

try{
  const response = await axios.get('https://newsapi.org/v2/top-headlines?country=kr&category=sports&apiKey=755b48e892b34cab8c2f6f7be92d8944')
  setData(response.data)
}

뉴스 뷰어 UI 만들기

현재 api 정보 확인하기

  • title: 제목
  • description : 내용
  • url : 링크
  • urlToImage:뉴스 이미지

styled-component

$ yarn add styled-component

사용 법 ⇒ 컴포넌트 변수로 만든다. styled 불러온 뒤 백틱으로 묶고 css 설정 해준 뒤

사용시 <컴포넌트> </컴포넌트> 사이에 적으면 styling 완료

NewsItem.js

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="nooperner noreferrer">
              <img src={urlToImage} alt="thumbnail"/>
            </a>
          </div>
        )}
        <div className="contents">
          <h2>
          <a href={url} target="_blank" rel="nooperner noreferrer">
            {title}
          </a>
          </h2>
          <p>{description}</p>
        </div>
      </NewsItemBlock>
    )
  }

export default NewsItem;

NewsList.js

리스트에서 Item들 보여주기

import styled from "styled-components";
import NewsItem from "./NewsItem";

const NewsListBlock = styled.div`
  box-sizing:border-box;
  padding-bottom:3rem;
  width:768px;
  margin:0 auto;
  margin-top:2rem;
  @media screen and (max-width:768){
    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 (
    <NewsListBlock>
      <NewsItem article={sampleArticle}/>
      <NewsItem article={sampleArticle}/>
      <NewsItem article={sampleArticle}/>
      <NewsItem article={sampleArticle}/>
      <NewsItem article={sampleArticle}/>
      <NewsItem article={sampleArticle}/>
    </NewsListBlock>
  )
}
export default NewsList

App.js

<NewsList/> 불러오기

데이터 연동하기

useEffect

useEffect 사용해서 컴포넌트가 처음 렌더링되는 시점에 API를 요청하면 된다.

  • async를 붙이면 안된다.
  • +로딩이 되는 중인것도 추가해주겠다.

Newslist.js

import styled from "styled-components";
import NewsItem from "./NewsItem";
import { useState,useEffect } from "react";
import axios from "../../../node_modules/axios/index";

const NewsList = ()=>{
  const [articles,setArticles]= useState(null);
  const [loading,setLoading] = useState(false)

  useEffect(()=>{
    const fetchData = async()=>{
      setLoading(true);
      try{
        const response = await axios.get(
          'https://newsapi.org/v2/top-headlines?country=kr&category=sports&apiKey=755b48e892b34cab8c2f6f7be92d8944'
        )
        setArticles(response.data.articles)
      }catch(e){
        console.log(e)
      }
      setLoading(false)
    }
    fetchData();
  },[])
  if(loading){
    return <NewsListBlock>대기중...</NewsListBlock>
  }
  if(!articles){
    return null
  }

  return (
    <NewsListBlock>
      {articles.map(article=>(
        <NewsItem key={article.url} article={article} />
      ))}
    </NewsListBlock>
  )
}
export default NewsList

주의

if(!articles){return null }

map 함수를 쓰기 전에 꼭 !articles를 조회하여 해당값이 현재 null인지 검사해야 한다.

아직 데이터가 없을 떄 null에는 map 함수가 없기 때문에 렌더링 과정에서 오류 발생한다.

profile
FE - devp

0개의 댓글