#04 리액트를 사용한 팬레터 웹사이트 개발
▼: 팬레터 등록 기능 구현 및 유효성 검사 , 글자수 제한 방법▼
React#04 리액트를 사용한 팬레터 웹사이트 개발 : 팬레터 등록 기능 구현 및 유효성 검사 , 글자수
#03 리액트를 사용한 팬레터 웹사이트 개발 ▼: DummyData로 리스트 UI 구현 및 클릭한 사람 데이터만 보이기 ▼ #03 리액트를 사용한 팬레터 웹사이트 개발 : DummyData로 리스트 UI 구현 및 클릭한 사람
zerotonine2da.tistory.com
개인프로젝트 (리액트 팬레터 홈페이지 만들기 ) 과제 해설
- 홈화면 팬레터 클릭시 상세페이지로 이동 (useNavigate 사용)
- 상세화면 UI 구현
- 공통 컴포넌트 적용 + 조건부 스타일
- 공통 함수 적용
- 홈버튼 (Link 사용)
(1) 홈 화면 팬레터 클릭시 상세페이지로 이동 (useNavigate 사용)
import { useNavigate } from 'react-router-dom';
export default function LetterCard({ letter }) {
const naviagte = useNavigate();
return (
<LetterWrapper onClick={() => naviagte(`/detail/${letter.id}`)}>
▶팬레터 클릭시 상세페이지로 이동 : useNaviagte() 사용
(2) 상세화면 UI 구현
import Avatar from 'components/common/Avatar';
import Button from 'components/common/Button';
import React from 'react';
import { useParams } from 'react-router-dom';
import styled from 'styled-components';
import { getFormattedDate } from 'util/data';
import { Link } from 'react-router-dom';
export default function Detail({ letters }) {
const { id } = useParams();
//구조분해할당으로 가져옴
const { avatar, nickname, createdAt, writedTo, content } = letters.find((letter) => letter.id === id);
console.log(avatar);
return (
<Container>
<Link to="/">
<HomeBtn>
<Button text="홈으로" />
</HomeBtn>
</Link>
<DetailWrapper>
<UserInfo>
<AvatarAndNickName>
<Avatar src={avatar} size="large" />
<NickName>{nickname}</NickName>
</AvatarAndNickName>
<time>{getFormattedDate(createdAt)}</time>
</UserInfo>
<ToMember>To: {writedTo}</ToMember>
<Content>{content}</Content>
<BtnWrapper>
<Button text="수정" />
<Button text="삭제" />
</BtnWrapper>
</DetailWrapper>
</Container>
);
}
▶구조분해할당으로 데이터를 가져와서 사용하기
▶버튼+이미지는 공통 컴포넌트 사용
▶상세페이지로 이동 & 홈화면으로 이동 (link)
(3-1) 공통 컴포넌트 : 이미지 사진
[components > common > Avatar.jsx]
import React from 'react';
import styled from 'styled-components';
import defaultUser from 'assets/person.png';
export default function Avata({ src, size }) {
return (
<AvatarFigure>
<img src={src ?? defaultUser} alt="아바타이미지" />
</AvatarFigure>
);
}
const AvatarFigure = styled.figure`
${(props) => {
switch (props.size) {
case 'large':
return css`
width: 100px;
height: 100px;
`;
default:
return css`
width: 50px;
height: 50px;
`;
}
}}
border-radius: 50%; /*동그라미 */
overflow: hidden; /*이미지가 삐져나오면 안보이게 */
& img {
width: 100%;
height: 100%;
object-fit: cover; /*figure크기만큼 꽉 차게 */
border-radius: 50%;
}
`;
▶src = 팬레터의 아바타 > props로 받아서 사용
▶상세페이지의 사진은 더 크게 주기위해서 조건부 스타일 적용
1) props로 받아온 size를 switch문을 통해 다르게 적용
▶주의사항 : props로 받을때는 구조분해할당으로 {src}로 받아야함 ! 안그러면 위에처럼 데이터가 있는데도 안나옴
[잘못] function Avatar(src) {
[정상] function Avatar({src}) {
[Detial.jsx]
<AvatarAndNickName>
<Avatar src={avatar} size="large" />
</AvatarAndNickName>
▶props로 size를 "large"로 전달
[LetterCard.jsx]
import Avatar from './common/Avatar';
<LetterWrapper onClick={() => naviagte(`/detail/${letter.id}`)}>
<UserInfo>
<Avatar src={letter.avatar} />
▶props로 src = {letter.avatar} 전달
(3-2) 공통 컴포넌트 : 버튼 (팬레터 등록 / 수정 / 삭제)
[components > common > Button.jsx]
import React from 'react';
import styled from 'styled-components';
export default function Button({ text }) {
return (
<BtnWrapper>
<button>{text}</button>
</BtnWrapper>
);
}
const BtnWrapper = styled.div`
display: flex;
justify-content: flex-end;
align-items: center;
& button {
background-color: #e09dd3;
color: white;
font-size: 16px;
padding: 6px 12px;
cursor: pointer;
border: none;
}
`;
▶공통 버튼 생성 : {text}로 팬레터 등록 / 수정 / 삭제 값 받아오기
[AddForm.jsx]
import Button from './common/Button';
<Button text="팬레터 등록" />
[Detail.jsx]
import Button from './common/Button';
<BtnWrapper>
<Button text="수정" />
<Button text="삭제" />
</BtnWrapper>
(4) 공통 함수 : 날짜 포맷 기능
[src> util > data.js]
export const getFormattedDate = (date) =>
new Date(date).toLocaleDateString('ko', {
year: '2-digit',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
▶ 매개변수로 date 받아와서 newData(매개변수 date) 넣기
▶ export해서 외부에서 사용
[LetterCard.jsx] 기존 코드
<NickNameAndData>
<p>{letter.nickname}</p>
<time>{formattedDate}</time>
</NickNameAndData>
[LetterCard.jsx] 공통함수 적용코드
<NickNameAndData>
<p>{letter.nickname}</p>
<time>{getFormattedDate(letter.createdAt)}</time>
</NickNameAndData>
▶매개변수 date 부분에 letter.createdAt 인자로 넣기
[Detail.jsx] 공통함수 적용코드 + 구조분해할당으로 데이터 가져오기
export default function Detail({ letters }) {
const { id } = useParams();
//구조분해할당으로 가져옴
const { avatar, nickname, createdAt, writedTo, content } = letters.find((letter) => letter.id === id);
<time>{getFormattedDate( createdAt )}</time>
)}
▶ props로 전달받은 팬레터들 (데이터)
1) useParams() : 클릭한 팬레터의 id값 알아냄
2) props로 전달받은 팬레터들 (데이터) 중에 find해서 클릭한 팬레터 데이터를 구조분해할당으로
avatar, nickname, createAt, writedTo, content 데이터 가져옴
3) createdAt : 작성일자 => 공통함수 적용코드로 사용!
(5) 홈 버튼 (Link 사용)
<Link to="/">
<HomeBtn>
<Button text="홈으로" />
</HomeBtn>
</Link>
▶ Link로 버튼을 감싸주고 <Link to=""> 를 사용.
끝.