본문 바로가기
Study/React

React ) HackerNews WebApp 제작을 통한 React 학습

by JongIk 2022. 5. 7.
반응형

React 로 HackerRank News WebApp 만들기

전체코드 보러가기

1.hook 브랜치에서 확인하실 수 있습니다.

사용기술

  • react- v18
  • react-router-dom - v6

실행화면

학습내용

react-router-dom 사용

  • App.js
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
<Router>
    <ToolBar />
    <Routes>
      <Route exact path="/" element={<NewsView />} />
      <Route path="/news" element={<NewsView />} />
      <Route path="/ask" element={<AskView />} />
      <Route path="/jobs" element={<JobsView />} />
      <Route path="/userInfo/:id" element={<UserInfo />} />
      <Route path="/askInfo/:id" element={<AskInfo />} />
    </Routes>
</Router>
  • <Route> 태그를 사용하기 위해서는 위와 같이 <Routes> 태그로 감싸줘야합니다.

  • path 에는 이동할 url 주소를 명시하고, element 에는 화면에 렌더링될 컴포넌트를 입력합니다.

  • ToolBar.js

import { Link } from "react-router-dom";

<Link to="/news" style={{ textDecoration: "none", margin: "0 5px" }}>
        News
</Link>

<Link to="/ask" style={{ textDecoration: "none", margin: "0 5px" }}>
        Ask
</Link>
<Link to="/jobs" style={{ textDecoration: "none", margin: "0 5px" }}>
        Jobs
</Link>
  • 클릭해서 해당 페이지로 넘어가고 싶을땐 <Link to="/"> 태그를 사용하면 됩니다.

useEffect, useState 사용

  • NewsList.js
import React, { useEffect, useState } from "react";

import { fetchNews } from "../../api/index.js";
function NewsList() {
  const [newsList, setNewsList] = useState([]);

  useEffect(() => {
    async function getNewsList() {
      // You can await here
      const response = await fetchNews();
      // ...
      setNewsList(response.data);
    }
    getNewsList();
  }, []);
  return (
    <ul>
      {newsList.map((newsItem) => (
        <li key={newsItem.id}>
          <div>
            {newsItem.points || 0}
          </div>
          <div>
            <p>
              {newsItem.title}
              <span>
                {newsItem.domain} {newsItem.user}
              </span>
            </p>
          </div>
        </li>
      ))}
    </ul>
  );
}
export default NewsList;
  • 화면에 렌더링될 newsList 변수를 useState 를 사용해 빈 배열로 먼저 선언했습니다.
  • useEffect 를 활용해 화면이 전환되자마자 getNewsList() 함수를 실행시켜 뉴스리스트를 받아왔고, setNewsList() 를 이용해 newsList 상태를 업데이트 했습니다.

조건부 렌더링

  • ListItem.js

위의 News 페이지와 Ask, Jobs 페이지는 비슷한 구조를 가지고 있기 때문에 ListItem.js 라는 파일을 생성해 한 파일에서 조건부 렌더링을 통해 3개의 리스트들을 다 출력해주기로 했습니다.

import React, { useEffect, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import { fetchAsk, fetchJobs, fetchNews } from "../../api";

export function ListItem() {
  const { pathname } = useLocation();
  const [ItemList, setItemList] = useState([]);

  const fetchList = async () => {
    if (pathname === "/news" || pathname === "/") {
      const newsList = await fetchNews();
      setItemList(newsList.data);
    } else if (pathname === "/ask") {
      const askList = await fetchAsk();
      setItemList(askList.data);
    } else if (pathname === "/jobs") {
      const jobsList = await fetchJobs();
      setItemList(jobsList.data);
    }
  };

  useEffect(() => {
    fetchList();
  }, []);

  return (
    <>
      <ul style={{ padding: "0", margin: "0" }}>
        {ItemList.map((Item) => (
          <linkey={Item.id}>
            <div>
              {Item.points || 0}
            </div>
            <div>
              <p style={{ margin: "0" }}>
                {/* domain 있을 때 */}
                {Item.domain && (
                  <span>
                    <a href={Item.url}>{Item.title}</a>
                    <small>{Item.domain}</small>
                  </span>
                )}
                {/* domain 없을 때 */}
                {!Item.domain && (
                  <span>
                    <Link to={{ pathname: `/askInfo/${Item.id}` }}>
                      {Item.title}
                    </Link>
                    <small>
                      <a href={Item.url}>{Item.domain}</a>
                    </small>
                  </span>
                )}
                {/* user 정보 있으면 표시 */}
                {Item.user && (
                  <small>
                    {" "}
                    by{" "}
                    <Link to={{ pathname: `/userInfo/${Item.user}` }}>
                      {Item.user}
                    </Link>
                  </small>
                )}
                {/* 작성시간 있으면 표시 */}
                {Item.time_ago && <small> {Item.time_ago}</small>}
              </p>
            </div>
          </li>
        ))}
      </ul>
    </>
  );
}
  • react-router-dom 의 useLocation 속성을 이용해 현재 페이지의 url 값을 추출한 뒤, url에 따라 ItemList 변수값에 담기는 정보들이 바뀌도록 했습니다.
  • 그리고 각각에 point, domain, user 등의 정보가 없는 경우를 && 연산자를 이용해 다르게 표시하도록 했습니다.

보완해야할 점

  • Redux와 Redux-Saga, Recoil 을 학습중에 있습니다.
  • 빨리 이 프로젝트에 적용해보고 싶네요..
반응형

댓글