Skip to content

13oosters/project-sns-react

Repository files navigation

🐶 멍하냥 🐱

스크린샷 2023-01-05 오전 1 40 20

소개 및 개요

[프로젝트 설명]

  • '멍하냥'은 반려동물들의 일상을 공유하는 SNS 플랫폼입니다.
  • '멍하냥'이라는 이름은 "뭐해?"라고 묻는 말에 강아지와 고양이를 나타내는 '멍'과 '냥'을 붙여 반려동물들의 안부를 묻는 의미를 담았습니다.
  • 사용자들은 자신의 반려동물 사진을 기록하고 자랑할 수 있습니다.
  • 다른 계정을 팔로우해서 팔로우한 사용자들의 게시물을 피드에서 한 번에 볼 수 있고, 댓글과 좋아요를 통해 서로 소통을 할 수 있습니다.

목차

1. 팀 소개

🚀 13oosters팀을 소개합니다!

안녕하세요, 저희는 4명의 Front-end 개발자로 구성된 13oosters팀입니다.
13이 영어 알파벳의 'B'와 비슷한 모양을 활용해 '부스터즈'라는 팀명을 지었습니다. boost는 신장시키다/북돋우다/격려/촉진 등의 의미를 가지고 있고, booster는 촉진제/추진로켓 등의 의미를 가지고 있습니다. 이번 프로젝트가 저희 성장의 촉진제가 되었으면 하는 마음에서 작명했습니다. 🚀🔥
(멋쟁이사자처럼 프론트엔드 스쿨 3기 프로젝트 13팀입니다.)

👑 이준근 🎨 김소영 💻 이준엽 📜 최현지
blog: jxxunnn
github: Jxxunnn
github: TommyKim97 blog: yubmun
github: yubmun
github: h12j21-star
FrontEnd
Team%20Leader
Development%20Leader
FrontEnd
Design%20Leader
FrontEnd
WorkManagement
FrontEnd
Communication%20Leader

(⬆️ Top)

2. 기술 및 개발 환경

[사용 기술]

  • Front-end :

  • Back-end : 제공된 API 사용


[개발 환경]

  • GitHub Projects : 진행상황을 page별로 나누어 GitHub Issues에서 각자 맡은 업무를 이슈 템플릿에 체크리스트 형식으로 공유했습니다.
  • GitHub Wiki : 회의와 컨벤션을 기록하고 요점노트를 기록하여 공유하였습니다.
  • Figma : 동시 접속하여 함께 UI, 색상 디자인 상의를 진행했습니다.
  • Discord, Gather Town : 원활한 의사소통을 위해 디스코드와 게더타운에서 영상 및 음성 통화를 적극 활용했습니다.

[git 흐름 전략]

페이지 별로 기능을 담당하여 프로젝트를 진행하고자 🔗 Git Flow 방식 을 사용했습니다. 페이지 별 브랜치를 만들고 각자 작업 브랜치를 따로 생성하여, 페이지 브랜치로 PR 및 Merge를 진행합니다.

[커밋 컨벤션]

🔗 커밋 컨벤션

- feat: 새로운 기능 구현
- fix: 오류 수정
- docs: 문서 수정 (예 : readme.md, json 파일 등 수정/ 문서 관련 라이브러리 설치 등)
- design: 마크업 및 style 작업
- style: 코드에 변화가 없는 수정 (예 : prettier, 세미콜론 등)
- refactor: 코드 리팩토링
- comment: 주석 추가
- chore: 빌드 부분 혹은 패키지 매니저 수정사항
- rename: 파일 혹은 폴더명 수정 or 옮기기
- remove: 파일 삭제

[코드 컨벤션]

통일성 있는 코드 작성을 위해 다양한 🔗 코드 컨벤션 을 정해 사용했습니다.

{
  "printWidth": 80,
  "singleQuote": false,
  "jsxSingleQuote": false,
  "tabWidth": 2,
  "semi": true,
  "trailingComma": "all",
  "bracketSpacing": true,
  "arrowParens": "always"
}

{
	"extends": ["react-app", "react-app/jest", "naver" "prettier"],
	"rules": {
		"no-console": 1,
        	"react-hooks/exhaustive-deps": 0,
        	"no-unused-expression": false
	}
}

[배포 서비스]


(⬆️ Top)

3. 개발 기간 및 작업 문화

[프로젝트 기간] : 2022.12.09. ~ 2023.01.04.


[작업 문화]

📍 GitHub Project

각자 맡은 업무를 이슈 템플릿에 체크리스트 형식으로 공유했습니다. image

📍 GitHub Wiki

  • 팀 노션에 동시 접속하여 🔗 주간 회의를 진행하고, GitHub Wiki에 회의 내용을 정리해 업로드했습니다.
  • 프로젝트에서 사용하는 Styled-Components의 공식문서를 번역하며 🔗 공부 내용을 기록하여 공유하였습니다.

image

📍 Gather Town & VSCode Live Share

  • 게더 타운의 가상 팀 공간을 활용하여 협업을 진행했습니다. 페어 프로그래밍을 진행하거나 전체 상의가 필요한 작업을 할 때, 게더 타운의 화면 공유와 음성 통화 기능과 VSCode의 Live Share 확장 기능을 적극 활용했습니다.

(⬆️ Top)

4. 주요 기능

🔒 로그인 / 회원가입

  • 로그인
  • 회원가입
  • 유효성 검사
  • 토큰 검증

📎 피드

  • 게시글 업로드
  • 무한 스크롤

🔍 검색

  • 유저 검색

🖼 게시글

  • 게시글 수정, 삭제
  • 댓글 게시, 삭제
  • 게시글/댓글 신고

👨🏿‍🤝‍👨🏼프로필

  • 로그아웃
  • 프로필 수정
  • 팔로우 / 팔로잉
  • 그리드, 리스트형 게시글

(⬆️ Top)

5. 프로젝트 구조

[폴더 구조]

  • assets/ : 이미지, 아이콘
  • components/ : 컴포넌트
  • components/common/ : 공통
  • pages/ : 생성한 컴포넌트들을 조합해 각 페이지 구현
  • style/ : globalstyle, 공통 스타일
  • utils/ : util 함수

📦 project-sns-react🐶😺
.eslintrc.json
.github
│  ├─ ISSUE_TEMPLATE
│  └─ PULL_REQUEST_TEMPLATE
├─ .gitignore
├─ .gitmessage.txt
├─ .prettierignore
├─ .prettierrc.json
├─ README.md
├─ package-lock.json
├─ package.json
├─ public
│  └─ index.html
└─ src
   ├─ App.js
   ├─ assets
   │  └─ image
   ├─ components
   │  ├─ common
   │  │  ├─ Card.js
   │  │  ├─ Cards.js
   │  │  ├─ Logo.js
   │  │  ├─ Modal.js
   │  │  ├─ Notice.js
   │  │  ├─ ProfileSetting.js
   │  │  └─ SplashScreen.js
   │  ├─ follow
   │  │  ├─ FollowersCard.js
   │  │  ├─ FollowersCards.js
   │  │  ├─ FollowingsCard.js
   │  │  └─ FollowingsCards.js
   │  ├─ home
   │  │  ├─ EmptyFeed.js
   │  │  ├─ Feeds.js
   │  │  ├─ Loading.js
   │  │  └─ PostImage.js
   │  ├─ login
   │  │  ├─ Form.js
   │  │  ├─ Login.js
   │  │  └─ Welcome.js
   │  ├─ post
   │  │  ├─ Comment.js
   │  │  ├─ Comments.js
   │  │  ├─ Detail.js
   │  │  ├─ Dialog.js
   │  │  └─ Writing.js
   │  ├─ profile
   │  │  ├─ GridCard.js
   │  │  ├─ GridCards.js
   │  │  ├─ MyProfileButton.js
   │  │  ├─ ProfileInformation.js
   │  │  └─ SortButtons.js
   │  ├─ search
   │  │  ├─ Result.js
   │  │  └─ Results.js
   │  ├─ style
   │  │  ├─ Button.js
   │  │  ├─ GlobalStyle.js
   │  │  ├─ Header.js
   │  │  ├─ NavBar.js
   │  │  ├─ PageLayout.js
   │  │  ├─ follow
   │  │  │  ├─ FollowButton.js
   │  │  │  └─ FollowCancelButton.js
   │  │  ├─ form
   │  │  │  ├─ ErrorMessageP.js
   │  │  │  ├─ LoginButton.js
   │  │  │  ├─ LoginForm.js
   │  │  │  ├─ LoginInput.js
   │  │  │  ├─ SignUpButton.js
   │  │  │  └─ TitleH2.js
   │  │  └─ profile
   │  │     ├─ FollowButton.js
   │  │     ├─ FollowCountDiv.js
   │  │     ├─ FollowCountP.js
   │  │     └─ FollowCountSpan.js
   │  └─ upload
   │     ├─ ImageUpload.js
   │     ├─ Posting.js
   │     └─ TextUpload.js
   ├─ hooks
   │  ├─ useFetch.js
   │  └─ useInput.js
   ├─ index.css
   ├─ index.js
   ├─ pages
   │  ├─ ErrorPage.js
   │  ├─ FollowersPage.js
   │  ├─ FollowingsPage.js
   │  ├─ HomePage.js
   │  ├─ LoginPage.js
   │  ├─ PostPage.js
   │  ├─ ProfileEditPage.js
   │  ├─ ProfilePage.js
   │  ├─ SearchPage.js
   │  └─ UploadPage.js
   ├─ reportWebVitals.js
   ├─ routes
   │  └─ Router.js
   └─ utils
      ├─ api.js
      ├─ postData.js
      └─ validate.js

(⬆️ Top)

6. 역할 분담

역할분담


(⬆️ Top)

7. UI

UI


(⬆️ Top)

8. 페이지 기능

  • 상세 기능 설명은 각 페이지별 링크 연결해두었습니다.

1) 홈

🔗 splash 🔗 로그인 페이지 🔗 회원가입 페이지
🔗 홈 페이지 🔗 검색 페이지

2) 프로필

🔗 마이 프로필 페이지 🔗 유저 프로필 페이지 🔗 팔로워 페이지 & 팔로잉 페이지
🔗 프로필 수정 페이지 🔗 로그아웃 모달

3) 게시글

🔗 게시글 작성 페이지 🔗 게시글 상세 페이지 🔗 홈 페이지 모달
🔗 게시글 수정 / 신고 모달 🔗 댓글 삭제 / 신고 모달

(⬆️ Top)

9. 핵심 기능

[Axios 모듈화]

axios로 서버와 통신하는 모든 부분에서 서버 주소와 코드가 반복되어 이를 줄이기 위해 custom axios를 사용하였습니다.

const BASE_URL = "url";

const API = axios.create({
  baseURL: BASE_URL,
  headers: {
    "Content-Type": "application/json",
  },
});

API.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem("token");

    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    Promise.reject(error);
  },
);

[Header 공통 컴포넌트 오브젝트 자료형 응용]

페이지 마다 존재하는 header의 구성이 비슷하여 공통 컴포넌트로 만들었고, 각 페이지에 type을 지정하여 각 페이지 별로 header를 구분하였습니다.

export default function Header({
  type,
  setKeyword,
  startTransition,
  setProfileModal,
  profileModal,
}) {
  const UI = {
    logo: (
     <HeaderUI>
        <button>
          <img src={topLogoImage} alt="멍하냥" />
        </button>
      </HeaderUI>
    ),
    search: (
    ),
    profile: (  
    ),
    post: (
    ),
    followers: (  
    ),
    followings: (
    ),
  };

  return <HeaderWrap>{UI[type]}</HeaderWrap>;
} 

[react-hook-form]

로그인 페이지 / 회원가입 페이지에서 유효성 검사를 react-hook-form 라이브러리를 사용했습니다. 입력 값 존재 여부, 포커스 등의 유틸을 지원하기 때문에 기능 구현의 리소스를 절약할 수 있었습니다.

 const {
    register,
    setFocus,
    handleSubmit,
    formState: { isSubmitting, errors },
    watch,
  } = useForm({ mode: "onChange" });
  
  const checkIsValue = (e) => {
    e.target.value && watch("email") && watch("password")
      ? setIsValue(true)
      : setIsValue(false);
  };

  const handleInput = (e) => {
    setUserData({ ...userData, [e.target.name]: e.target.value });
    checkIsValue(e);
  };
...


[검색 페이지 렌더링 성능 최적화]

검색 페이지에서는 Blocking rendering을 해결하여 성능을 최적화하는 것이 중요하다고 생각했습니다. 이를 위해 useTransition 훅을 사용하였습니다.

📍 useTransition 특징

  • useTransition은 상태변화의 우선순위를 지정해줍니다.
  • 화면을 업데이트 하는 중에도 검색 input의 우선순위를 높여 입력이 끊기는 상황을 줄여줍니다.
  • isPending의 boolean값을 이용하여 로딩중 ui를 띄어 ux를 향상 시켜줍니다.
export default function SearchPage() {
  const [keyword, setKeyword] = useState(undefined);
  const [isPending, startTransition] = useTransition();

  return (
    <PageLayout paddingValue={0}>
      <h1 className="sr-only">검색 페이지</h1>
      <Header
        setKeyword={setKeyword}
        startTransition={startTransition}
        type="search"
      />
      <Results keyword={keyword} isPending={isPending} />
      <NavBar type="검색" />
    </PageLayout>
  );
}
...

search: (
      <>
        <h2 className="sr-only">검색창</h2>
        <HeaderUI>
          <button onClick={() => navigate(-1)}>
            <img src={backImage} alt="뒤로 가기" />
          </button>
          <SearchDiv>
            <HeaderInput
              onKeyUp={(e) => {
                startTransition(() => {
                  setKeyword(e.target.value);
                });
              }}
              placeholder="계정 검색"
            />
            <button
              onClick={(e) => {
                e.target.closest("div").childNodes[0].value = "";
                setKeyword("");
                //
              }}
              type="button"
            >
              <img src={cancelImage} alt="취소 버튼" />
            </button>
          </SearchDiv>
        </HeaderUI>
      </>
    )

(⬆️ Top)

10. 느낀 점

🐱 준근

  • 이번 프로젝트를 통해 학습하고 성장하자는 공동의 목표로 의미있는 과정을 남긴 것 같아 뿌듯합니다. 개발하는 재미를 다시금 느끼게 해준 팀원들 감사합니다.

🐶 소영

  • 정말 멋지고 좋은 팀원 분들을 만나서 많은 것들을 배울 수 있었던 감사한 시간이었습니다. 함께 프로젝트 하게 되어 영광이었고, 같이 즐거웠던 일화들도 소중한 기억으로 남을 것 같습니다. 🚀💗

🐹 준엽

  • 여러모로 부족한 상태로 프로젝트를 시작했지만, 팀원분들의 유쾌한 응원과 기술 구현에 대한 지식공유를 해주셔서 여러 경험들을 할 수 있는 행복한 시간이었습니다. 정말 고생많으셨습니다~!

🐰 현지

  • 이번 프로젝트를 통해 자신감을 많이 얻었고 협업과정과 커뮤니케이션을 배울 수 있었습니다. 다들 정말 감사하고 수고하셨습니다~!💜


(⬆️ Top)

About

커뮤니티 중시형 SNS 앱 만들기 프로젝트

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •