스파르타 기간 동안의 TIL
오늘의 공부를 끝내며.. (12/28)
푸른매실
2022. 12. 28. 20:28
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import { useNavigate } from "react-router-dom";
import Layout from "../components/Layout";
import { Dropdown, DropdownButton, Form, InputGroup } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import { __getPostThunk } from "../redux/modules/mainupdateSlice";
import ReactHtmlParser from "react-html-parser";
import ReactStars from "react-rating-stars-component";
import { ScrollToTop } from "../components/ScrollToTop";
import Weather from "./Weather";
import "bootstrap/dist/css/bootstrap.min.css";
import inga from "../img/inga_bbang.jpg";
const Home = () => {
const dispatch = useDispatch();
const { posts, isLoading } = useSelector((state) => state.mainupdateSlice);
const [searched, setSearched] = useState([]);
useEffect(() => {
setSearched([...posts]);
}, [posts]);
const getValue = (e) => {
const aa = e.target.value.toLowerCase("posts");
setSearched(
posts.filter(
(item) =>
item.content.toLowerCase().includes(aa) ||
item.title.toLowerCase().includes(aa) ||
item.user_id.toLowerCase().includes(aa)
)
);
};
const setRead = (e) => {
e = e + 1;
};
const navigate = useNavigate();
useEffect(() => {
dispatch(__getPostThunk());
}, []);
if (isLoading) {
return (
<>
<img src="/logo.png" height="58" alt="" /> "로딩중...."
</>
);
}
return (
<Layout>
<Weather />
<MainBox>
{/* 버튼 클릭 시 스크롤을 맨 위로 올려주는 컴포넌트 */}
<ScrollToTop />
<InputGroup className="mb-3">
<Form.Control
placeholder="검색하고 싶은 제목이나 내용, 아이디를 입력하세요"
aria-label="Recipient's username"
aria-describedby="basic-addon2"
style={{ height: "60px", fontSize: "20px" }}
onChange={getValue}
/>
</InputGroup>
<SortBox>
<DropdownButton id="dropdown-item-button" title="---정렬---">
<Dropdown.Item
onClick={() => {
setSearched([...posts]);
}}
as="button"
>
전체
</Dropdown.Item>
<Dropdown.Item
onClick={() => {
setSearched([...posts].sort((a, b) => a.rate - b.rate));
}}
as="button"
>
평점순
</Dropdown.Item>
<Dropdown.Item
onClick={() => {
setSearched([...posts].sort((a, b) => a.read - b.read));
}}
as="button"
>
조회순
</Dropdown.Item>
</DropdownButton>
</SortBox>
{/* 글목록 */}
<ItemContainer>
<Items>
{searched
?.slice(0)
.reverse()
.map((posts) => (
<Item
key={posts.id}
onClick={() => {
setRead(posts.read);
// console.log(posts.read);
navigate(`/${posts.id}`);
}}
>
<RatingBox>
<ReactStars
count={posts.rate}
size={30}
color="#f2d589"
activeColor="#f2d589"
></ReactStars>
</RatingBox>
<TitleBox>{posts.title}</TitleBox>
<ContentBox>{ReactHtmlParser(posts.content)}</ContentBox>
<UserNameBox>{posts.user_id}</UserNameBox>
</Item>
// 잔여연산자 사용
))}
</Items>
</ItemContainer>
</MainBox>
</Layout>
);
};
export default Home;
const MainBox = styled.main`
background-image: url(${inga});
background-size: cover;
background-repeat: no-repeat;
background-attachment: fixed;
min-height: 100vh;
`;
const SortBox = styled.section`
display: flex;
text-align: right;
justify-content: flex-end;
border-top: 3px solid #f2d589;
padding-top: 10px;
box-sizing: inherit;
margin-bottom: 15px;
`;
const ItemContainer = styled.div`
display: flex;
margin: 0 auto;
box-sizing: inherit;
`;
const Items = styled.ul`
justify-content: center;
list-style: none;
margin: 0 auto;
display: flex;
grid-gap: 35px;
gap: 35px;
flex-wrap: wrap;
padding: 0;
box-sizing: inherit;
`;
const Item = styled.div`
opacity: 1;
display: flex;
flex-direction: column;
justify-content: center;
padding: 40px 26px 26px 34px;
width: 300px;
height: 370px;
background-color: #fff;
border: 2px solid #f2d589;
border-radius: 30px;
position: relative;
cursor: pointer;
transition: 0.2s;
box-sizing: inherit;
&:hover {
text-decoration: none;
color: #f2d589;
width: 310px;
height: 380px;
}
`;
const TitleBox = styled.h2`
font-size: 20px;
height: 76px;
line-height: 28px;
font-weight: 500;
letter-spacing: -0.04em;
margin: 16px 0;
word-break: break-all;
overflow: hidden;
box-sizing: inherit;
`;
const ContentBox = styled.p`
font-size: 16px;
height: 160px;
line-height: 24px;
font-weight: 400;
letter-spacing: -0.04em;
margin: 11px 0;
word-break: break-all;
overflow: hidden;
box-sizing: inherit;
`;
const UserNameBox = styled.div`
font-size: 18px;
border-top: 2px solid #f0e0b5;
padding-top: 16px;
color: #f2d589;
font-weight: 700;
box-sizing: inherit;
`;
const RatingBox = styled.div`
font-size: 20px;
box-sizing: inherit;
`;
상당히 길어보이는 이 코드는 이번 프로젝트때 내가 메인화면 당담이기에, 메인화면의 코드들만 적어놨다 그리고, 메인화면에는 다음과 같다.
오른쪽 화면 처럼 글들을 불러오게 되며, 새 글을 쓰면 맨위에 추가된다. 그리고 검색기능과 정렬기능이 있는데, 평점순 조회순 전체 이렇게 3가지를 볼수 있다.(thunk로 쉽게 할수 있는것을 js로 힘들게 쳤음 ㅠㅠㅠ) 나머지 UI나 기능들에 대해서는 팀원들의 도움으로 전체적인 완성을 향해 나갔다. 이번 프로젝트에서는 사실 리덕스와 썽크 개념을 제대로 응용하지 못헀기에 , 난이도는 매우높음으로 생각한다.
그러나 좋은 소식은 다음에 배우는 언어가 리액트 네이티브이고, 리액트와 거의 비슷한 언어라는 것이다. 그렇기에 지금 배우는것에서 조금 더 추가하면 된다고 생각된다. 이전에는 새로운 언어를 배워야하기에 다시 기존 개념을 잊고 새로운것에 적응하다보니, 이전에 배웠던 것들을 거의 다 잊어버리는 아쉬운 부분이 있었지만, 이번에는 리액트 네이티브라는 연결점이 있기에 매우 긍정적으로 생각한다. 무사히 프로젝트에서 필수기능과 추가기능을 모두 구현할 수 있었고, 발표 및 자료제출도 잘 마쳐졌다. (서버배포부분만 빼고 ^^;;)
그리고 이제 짧지만 시작될 1주 뒤에 또 프로젝트가 시작된다..... 팀플의 연속이지만 이것도 반복되면 나름 적응되는것 같다 .