스파르타코딩클럽 내일배움캠프 TIL39

한재창·2022년 12월 22일
0

프로젝트 시작

  • React 주특기를 이용한 팀 프로젝트가 드디어 시작되었다. 우리 팀은 blind 사이트를 참고하여 커뮤니티 사이트를 만들기로 하였다.
  • 내가 맡은 일은 MainContent 컴포넌트를 만드는 일이다.
    • MainConetnt
      • 각각의 page 맞는 해당 글을 가지고 오기
        • json server
        • db자료를 하나씩 동적으로 처리
      • 시간 처리
      • 상세 페이지 이동 router 설정
      • cdn top button
      • 할 수 있다면 무한스크롤
  • 팀 노션 링크 ( 만든사람 - 팀장 배성완님, 감사합니다. ) : https://www.notion.so/Team-Homme-bcf1827f3fab4008ae04c7a586758762

폴더 구성

  • 아직 진행중이고, 쓸모없는 파일들은 지울 예정

탑 버튼 만들기

  • 스크롤이 어느 정도 내려갔을 때 TOP 버튼을 보여주기 위해 버튼 상태를 useState로 boolean 값을 주었다.
  • onShowTopButton 이라는 함수에서 조건문을 사용하여, scrollY 축이 400 이상으로 내려가면 버튼 상태를 true로 바꿔주고 아니라면 false
  • onClickTopHandler 함수는 클릭시 맨 위로 가는 이벤트 함수이다.
  • 이미 맨 위에 있을 경우는 어차피 맨 위에서 top 버튼이 보이지 않으므로 if(!window.scrollY) return; 코드를 삭제했다.
  • window.scrollTo 메서드를 이용해서 top 0의 위치로, 스무스하게 이동하도록 하고, 버튼 상태는 다시 false로 바꿨다.
  • 스크롤 이벤트 리스너는 계속 실행되기 때문에 useEffect를 통해 이벤트를 제거하였다. (사실 이 부분이 잘 이해가 되지 않는다..)
  • 마지막으로 버튼의 상태가 true 이면 버튼이 보이게, 아니면 null
import React, { useState, useEffect } from "react";
import {
  PositionContainer,
  TopBtn,
} from "../../../styledComponenet/mainContent";

export default function TopButton() {
  // 버튼 상태
  const [BtnStatus, setBtnStatus] = useState(false);

  // Y축 스크롤 위치에 따라 Show || Hide 함수
  const onShowTopButton = () => {
    if (window.scrollY > 400) setBtnStatus(true);
    else setBtnStatus(false);
  };

  // 클릭시 맨 위로 가는 이벤트
  const onClickTopHandler = () => {
    window.scrollTo({
      top: 0,
      behavior: "smooth",
    });
    setBtnStatus(false);
  };

  useEffect(() => {
    const watch = () => {
      window.addEventListener("scroll", onShowTopButton);
      console.log("watch");
    };
    watch();
    return () => {
      window.removeEventListener("scroll", onShowTopButton);
      console.log("remove");
    };
  });

  return (
    <PositionContainer>
      {BtnStatus ? <TopBtn onClick={onClickTopHandler}>🔝</TopBtn> : null}
    </PositionContainer>
  );
}

조건부 렌더링

  • 홈페이지, 디테일페이지, nav바를 눌렀을 때 페이지, 주소를 잘못 입력했을 때 페이지 총 4가지의 페이지를 만들었다.
  • 디테일 페이지와 카테고리 페이지는 각 항목을 클릭했을 때 useParams() 를 이용해 조건에 맞는 페이지를 렌더링하게 하였다.
// Rouser.js

import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Detail from "../page/Detail";
import HomePage from "../page/HomePage";
import JavascriptPage from "../page/JavascriptPage";
import NotFound from "../page/NotFound";

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="detail/:id" element={<Detail />} />
        <Route path=":category" element={<JavascriptPage />} />
        <Route path="NotFound" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;
  • useParams() 를 이용해서 주소의 /:category 의 값과 lists 에 있는 각각의 데이터들의 category의 값이 같은 것들만 filter 해서 새로운 배열을 만들어 준다.
  • category 가 undefined 일 때 즉 아무 값도 없을 때(Home 화면에 있을 때) 와 category가 "All" 일 때는 "All"로 표시한다.
  • Home 화면에 있을 때는 모든 데이터가 들어있는 lists로 맵을 돌리고, 아니라면 filter 배열인 list로 map을 돌린다.
  • /:category 의 값이 undefined, "All", "Redux", "React", "Css", "JavaScript" 가 아닐 때는 useNavigate() 훅을 사용하여 /NotFound 로 이동하게 하였다.
  • 각각의 카테고리들은 오타가 날 수 있기 때문에 추후에 상수로 바꿔 줄 예정이다.
// MainContent.jsx

import React, { useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import axios from "axios";
import { MainContentWrap } from "../../../styledComponenet/mainContent";

import ContentItems from "./ContentItems";
import TopButton from "./TopButton";

function MainContent() {
  const [lists, setLists] = useState([]);
  const navigate = useNavigate();
  const { category } = useParams();

  // 데이터를 가져와서 lists에 넣어 준다.
  const fetchTodos = async () => {
    const { data } = await axios.get("http://localhost:3010/Item/");
    setLists(data);
  };

  // 마운트 시 한번만 데이터 가져옴
  useEffect(() => {
    fetchTodos();
  }, []);

  const list = lists.filter((item) => item.category === category);

  console.log(category);
  return (
    <>
      <MainContentWrap>
        {category === "All" || category === undefined
          ? lists.map((item) => <ContentItems key={item.id} item={item} />)
          : category === "JavaScript" ||
            category === "Css" ||
            category === "React" ||
            category === "Redux"
          ? list.map((item) => <ContentItems key={item.id} item={item} />)
          : navigate("/NotFound")}
        <TopButton />
      </MainContentWrap>
    </>
  );
}

export default MainContent;
  • 박스 전체에 onClick 이벤트를 주었다.
  • useNavigate() 훅을 사용하여 박스를 클릭시 /detail/해당 아이디 로 페이지 이동이 가능하게 설정하였다.
// ContentItems.jsx

import React from "react";
import { useNavigate } from "react-router-dom";
import {
  ListBox,
  PageText,
  ListFooterBox,
  ItemWriter,
  Figcaption,
} from "../../../styledComponenet/mainContent";

import Time from "./Time";

function ContentItems({ item }) {
  const navigate = useNavigate();

  return (
    <ListBox onClick={() => navigate(`/detail/${item.id}`)}>
      <figure>
        <PageText>{item.category}</PageText>
        <h2>{item.title}</h2>
        <p>
          {item.content.length > 100
            ? item.content.slice(0, 100) + "..."
            : item.content}
        </p>
        <ListFooterBox>
          <ItemWriter>{item.writer}</ItemWriter>
          <Time />
        </ListFooterBox>
        <Figcaption>자세히보기</Figcaption>
      </figure>
    </ListBox>
  );
}

export default ContentItems;
profile
취준 개발자

0개의 댓글