프로젝트 시작
- 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);
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()
를 이용해 조건에 맞는 페이지를 렌더링하게 하였다.
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 로 이동하게 하였다.
- 각각의 카테고리들은 오타가 날 수 있기 때문에 추후에 상수로 바꿔 줄 예정이다.
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();
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/해당 아이디
로 페이지 이동이 가능하게 설정하였다.
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;