멋쟁이 사자처럼 프론트엔드 스쿨 6기와 이듬을 위한 SNS
목차
기간 : 2023 / 08 / 30 ~ 2023 / 09 / 24
npm i
| pnpm i
react
➡️ 18.2.0react-helmet-async
➡️ 1.3.0react-hot-toast
➡️ 2.4.1prop-types
➡️ 15.8.1framer-motion
➡️ 10.16.2@tanstack/react-query
➡️ 4.35.0browser-image-resizer
➡️ 2.4.1pocketbase
➡️ 0.18.0vite
➡️ 4.4.5vite-plugin-svgr
➡️ 3.2.0tailwindcss
➡️ 3.3.3postcss
➡️ 8.4.29autoprefixer
➡️ 10.4.15prettier
➡️ 3.0.3prettier-plugin-tailwindcss
➡️ 0.5.4eslint
➡️ 8.45.0pockethost
의 feeds
컬렉션에서 getList
로 게시글 2개씩 보여질 수 있도록 나열함.localstorage
에 저장된 로그인한 해당 사용자의 글만 불러오도록 filter
로 조건 처리하여 데이터 불러옴.onClick
이벤트를 통해 정보를 수정할 수 있는 모달창이 보여집니다.const [openModal, setOpenModal] = useState(false);
을 통해 모달 창을 열고 닫는 상태를 제어하고, 처음은 닫혀 있으므로 false 설정되어 있습니다.pockethost
의 update
를 이용하여 편집 기능 구현update
하고 서버로 전송되며 정보가 변경됩니다.pockethost
의 delete
를 이용하여 삭제 기능 구현pockethost
내에서의 게시글, 댓글, 답글의 데이터가 삭제되며 UI에서도 게시글이 사라지고 삭제되었다는 알림창이 보여집니다.deleteMyFeed
에서 ‘item, id, commentArray’
를 매개변수로 넘겨주어 onClick
이 발생했을 때 삭제 기능을 수행합니다.tabIndex
속성을 지정해줌으로써 키보드로 이동하고 사용 가능하도록 접근성을 높여줌.aria-label
을 사용하여 스크린 리더 사용자에게 정확한 정보를 전달하도록 함.role="dialog" //dialog 영역임을 알려줌
aria-labelledby="ProfileEdit" // 모달창 id 값 설정
aria-modal="true" // dialog 영역 이외의 본문이 선택되지 않도록
리액트에 대한 이해를 높일 수 있었던 경험이었습니다.
다양한 라이브러리를 직접 사용해보며 상태 관리, 성능 등 어떠한 문제를 개선할 수 있는지 사용 이유에 대해 알 수 있었습니다. 또한 크고 작은 문제 상황을 마주하며 리액트의 컴포넌트 설계가 중요한 이유도 깨달았습니다.
이번 프로젝트를 통해 리액트에 대한 이해와 팀원들과 소통하며 공유하는 과정을 통해 협업의 중요성을 느낄 수 있었습니다.
header
영역에는 로그인한 사용자의 프로필 이미지와 닉네임이 렌더링됩니다.
Component
로 구성하여, props
로 size
와 url
을 받아 재사용하였습니다.nav
영역에는 채널 목록이 구현되어 있으며, 기본으로는 전체 게시글
채널이 활성화됩니다.
main
영역에는 useInfiniteQuery
로 불러와진 게시글들이 렌더링됩니다.
Component
로 구성하여 게시글 페이지에서도 재사용하였습니다.닉네임
, 작성 시간
, 댓글 수
의 정보가 렌더링됩니다.context
로 관리하여, 사용자가 직접 입력한 페이지 주소와 클릭한 채널에 따라 선택된 채널 상태가 변경됩니다.
Tanstack Query
의 useInfiniteQuery
가 사용되었고, queryKey
에 window.location.pathname
을 전달하여, 채널을 바뀌는 경우에 데이터를 다시 불러오며, 한번 불러온 게시글들은 데이터를 다시 불러오지 않습니다.tab
과 관련된 role
, aria-
속성을 적절하게 부여하였고, 키보드로 컨트롤이 가능합니다.tab
을 누르게 되면 focus
됩니다.useInfiniteScroll
을 사용해, 한 페이지에 4개의 게시글들이 출력되며, IntersectionObserver
을 사용하여 하단으로 일정 부분 이상 스크롤할 경우 다음 페이지의 게시글들을 불러와 화면에 렌더링됩니다.답글 달기
버튼을 누르면, 답글을 달 수 있는 모달 영역이 열립니다.
focus
가 되며, 입력 후 작성하기를 클릭할 경우, 댓글과 동일하게 새로 데이터를 불러와 화면에 렌더링합니다.focus
를 가져갈 수 없도록 하였습니다.이번에는 프로젝트의 기간이 더 길어진 만큼 전 프로젝트에서는 신경쓰지 못했던 디렉토리 구성에 대한 부분이나, 네이밍, 웹 접근성에 대해서도 더 많이 고민해봤다.
대부분 수업시간의 디렉토리 구성을 참고하긴 했지만, 나름대로 더 좋겠다는 방향으로 구성해봤고, 네이밍에 대해서는 네이밍의 길이를 신경쓰지 않고, 어떤 동작을 하는지 이름으로 보다 더 알 수 있도록 고민했다. HTML/CSS와 JavaScript 프로젝트에서는 웹 접근성에 대해서는 많이 신경쓰지 못했는데, 이번에는 키보드 컨트롤도 신경써보고, 스크린 리더를 사용해 음성도 들어보며 접근성이 좋아지도록 노력했다.
이번에 배운 React를 사용하며, Side Effect를 최소화하려고 노력했고, 커스텀 훅에 대해서 조금은 더 이해한 것 같다. 하지만 아직도 상태를 누가 가지고, 어디로 넘겨줘야 하는지가 어려웠다. 굳이 context를 쓰지 않아도 될 것 같은 부분에서, 달리 방법을 찾지 못해 context를 구성한 것이 아쉽다.
Tanstack Query를 사용할 때, 공식문서를 읽어보려고 노력했지만 공식문서의 내용이 단조로운 것 같아 공식문서만 참고하여 사용하는 것이 어려웠다.
팀원과 시안을 만드는 것에 어려움이 있어서, 만든 서비스의 디자인이 단조로운 것 같아 아쉽고, 애니메이션을 사용해보지 못한 점이 아쉽다.
그래도, 처음에 가졌던 목표인, '완성도 있게 만들기'는 만족할 만큼 달성한 것 같다.
await pb.collection('users').authWithPassword(email, password);
function ProtectedRoute({ children }) {
return pb.authStore.isValid ? children : <Navigate to="/signin" />;
}
const renderfile = e.target.files[0];
if (renderfile) {
try {
// 이미지 리사이징 및 압축
const optimizedImage = await readAndCompressImage(renderfile, config);
// 선택된 이미지의 URL 생성
setSelectedImage(URL.createObjectURL(optimizedImage));
// 최적화된 이미지 파일 저장
setChangeImage(optimizedImage);
} catch (err) {
console.error('Failed to optimize image', err);
}
const handleUpdateClick = useCallback(async () => {
if (textValue === '') {
toast.error('텍스트를 입력해 주세요.');
return;
}
const updateData = { channels: channelsRef.current.value };
if (changeImage !== null) {
updateData.feed_image = changeImage;
}
if (textValue) {
updateData.text = textValue;
}
await pb.collection('feeds').update(data.id, updateData);
await refetch();
toast.success('게시글이 성공적으로 수정 되었습니다!');
navigate('/mypage');
}, [navigate, textValue, changeImage]);
프론트엔드 과정 중 약 한달 동안 리액트를 배웠는데 배우면서도 어떻게 리액트 프로젝트를 할 수 있을지 자바스크립트 프로젝트 때보다 더 막막하고 두려웠었다. 아직 자바스크립트에 대한 실력도 많이 부족했고 리액트는 자바스크립트와 비슷하면서도 다른 부분들이 꽤나 많아서 걱정이 가득한 상태에서 프로젝트에 들어갔던 것 같다.
프로젝트 기획 단계에서 만들고 싶은 서비스를 처음으로 피그마를 이용하여 시안을 만들어 보았고 피그마도 잘 다루지 못 해 시안 만들때 시간을 많이 할애하긴 했지만 직접 구현하고 싶은 서비스에 대한 시안을 만들면서 뿌듯함도 많이 느꼈다. 리액트 프로젝트는 전에 겪었던 다른 프로젝트들보다 기간이 길 뿐더러 하나부터 열까지 모두 다 구현해야 했기 문에 걱정도 많이 됐지만 막상 팀원들과 함께 일정도 짜고 회의도 많이 하면서 재미를 느꼈다.✌🏻
이번 프로젝트에서는 회원가입 페이지와 글쓰기 페이지를 담당하였는데 회원가입 페이지는 전 프로젝트에서도 항상 있었던 페이지였지만 직접 구현해본적은 없었는데 이번에 구현해보면서 처음으로 정규 표현식 사용을 해보면서 하나하나 꼼꼼하게 유효성 검사를 해보았는데 회원가입에서 생각보다 많은 경우의 수와 조건을 처리해야 한다는 것을 느꼈다. 그리고 아직 서버와 통신하는 부분이 서툴다보니 두 페이지 모두 그 부분에서 데이터를 보내고 생성하는 부분에서 시간을 제일 많이 할애했던 것 같은데 그 과정에서 발생한 에러들도 해결해보고 어떻게 리액트가 서버와 통신한 것을 화면에 렌더링 시켜주는지도 프로젝트를 통해 확실히 이해한 것 같다.
다만 아쉬운 점으로는 내가 맡은 페이지에 없었던 서비스에서 피드 페이지 부분에 있는 infinite scroll, 데이터에서 관계형으로 묶인 데이터들을 불러오고 생성하는 기능, 서버 상태 관리 부분을 제대로 경험해보지 못 한 것인데 프로젝트가 끝난 후 개인적으로 어떻게 구현하는지 방법을 연구해보고 싶다.
마지막 프로젝트여서 많이 아쉽기도 하고 4개월동안 정말 많이 힘들었지만 처음과 비교했을 때 많이 성장한 것 같다.😎 아직도 많이 서툴긴 하지만 4개월동안 배운 것을 기반으로 프론트엔드 개발자가 되기 위해 추가적인 학습들을 꾸준히 해서 좋은 결과를 얻고 싶다!
3주동안 함께 프로젝트 하느라 고생한 팀원들과 그동안 열정적으로 가르쳐주신 3분의 강사님들, 4개월동안 같이 열심히 과정을 끝마친 6기 동기분들께 감사의 인사를 드리고 싶습니다.🙇🏻♀️