1차 프로젝트 회고

이택우·2022년 5월 31일
0

프로젝트 회고

목록 보기
1/4

Team Project 1 - Soongo


생활 서비스 매칭 서비스 프로젝트 숭고

프로젝트 깃헙 링크


Challenging Points :

  • 컴포넌트 교체가 많이 일어나는 페이지에서의 input 값 관리
  • 언마운트된 컴포넌트가 state에 접근하여 생기는 메모리 누수 방지
  • 컴포넌트가 unmount된 이후에 다시 mount될 때, 이전에 입력한 값을 그대로 유지 (ex - 언마운트 이전에 체크된 체크박스 그대로 유지)
  • fetch로 설문 데이터를 받아서 가공한 뒤 다시 서버로 보내는 과정

고수 회원가입 / 일반 회원가입 구현

1 고수 카테고리 (분야) 선택

2 첫 페이지에서 선택한 분야를 params id로 fetch를 보내어 각기 다른 설문지를 받아옴

3 2에서 선택한 정보를 저장한 뒤 컴포넌트를 언마운트 시키고 기타 상세 정보를 입력.

2~3페이지에서는 URL이 바뀌지 않고 하단의 Nav바로 컴포넌트를 교체함.

(일반 회원가입은 3번 페이지와 동일)

고수 회원가입 분야 선택 이후 세부 질문 페이지

function MasterSignUpNext() {
  // api로 카테고리마다 다른 질문 받아오기 fetch('고수 가입 질문 get api url')
  // Parent-Category, Child-Category의 데이터 형태를 백엔드에서 어떻게 넘길 지 알아야함.
  // 고수 가입 상세 기입은 2페이지로 구성. 하위 카테고리 -> 고수 개인 정보
  const params = useParams();
  const [questions, setQuestions] = useState([]);
  const lessonCategory = useRef([]);
  const addressRef = useRef('');
	// 고수 회원가입 페이지 전역으로 인풋값 관리
  const masterInfo = useRef({
    name: '',
    email: '',
    phoneNumber: '',
    detailAddress: '',
    address: '',
    lessonCatID: lessonCategory.current,
  });

  useEffect(() => {
    let isMounted = true;
    fetch(`${SERVER_PORT}/category/${params.id}`, {
      method: 'GET',
    })
      .then(res => {
        return res.json();
      })
      .then(data => {
        if (isMounted) {
          setQuestions(data);
        }
      });
    return () => (isMounted = false);
  }, []);
  // api로 설문 결과 보내기

  const [formPage, setFormPage] = useState(0);
  // useMemo를 이용해서 리렌더링을 막는다. 이 페이지에서
  // + formComponentkey를 쓸 필요가 없다. 함수형 컴포넌트 밖에서 변수를 선언해준다.
  return (
    <section className={styles.section}>
      <div className={styles.container}>
        <div className={styles.progressbarBox}>
          <div className={styles.barContainer}>
            <div
              className={
                formPage === 0
                  ? styles.barProgress
                  : `${styles.barProgress} ${styles.bar100}`
              }
            />
          </div>
          <p className={styles.progressNumber}>
            {formPage === 0 ? '50%' : '100%'}
          </p>
        </div>
        <form className={styles.formBox}>
          {formPage === 0 ? (
            <FormBox
              questions={questions}
              questionKey={questionKey}
              key={formComponentKey++}
              lessonCategory={lessonCategory.current}
            />
          ) : (
            <FormInfo
              key={formComponentKey++}
              masterInfo={masterInfo}
              addressRef={addressRef}
            />
          )}
        </form>
      </div>
      <MasterSignUpFooter
        setFormPage={setFormPage}
        pageNumber={formPage}
        allData={masterInfo}
        checkLesson={lessonCategory.current}
        addressRef={addressRef}
      />
    </section>
  );
}

고수 상세정보

  • 해당 고수 상세 정보를 params로 get하여 페이지 렌더링
  • 페이지 내부 scroll nav바로 해당 섹션으로 이동

고수 정보 GET fetch 함수

function MasterDetail() {
  const params = useParams();
  const [master, setMaster] = useState({});
  const [reviews, setReviews] = useState([{ name: '' }]);
  const PORT = process.env.REACT_APP_SERVER_PORT;
.
.
.

  //get master profile fetch
  useEffect(() => {
    fetch(`${PORT}/master/users/${params.id}`, {
      method: 'GET',
    })
      .then(res => res.json())
      .then(data => {
        setMaster(data);
      });
  }, []);

  //get reviews
  useEffect(() => {
    fetch(`${PORT}/review/${params.id}`, { method: 'GET' })
      .then(res => res.json())
      .then(data => {
        if (data.reviews.length === 0) {
          data.reviews = [{ name: '' }];
        }
        setReviews(data.reviews);
      });
  }, []);

페이지 내부 scroll nav 바

function MasterDetailNav(props) {
  // navbar 이동 추가 구현
  const { master, masterInfo, masterReview, masterMedia, reviewCounts } = props;
  const { review } = master;
  const [active, setActive] = useState('');

  const scroll = ref => {
    ref.current.scrollIntoView({ behavior: 'smooth' });
    // header, detail nav bar height 제외하고 이동
  };

  const select = e => {
    setActive(e.target.innerText);
  };

  return (
    <ul className={styles.container}>
      <li
        onClick={e => {
          select(e);
          scroll(masterInfo);
        }}
        className={active === '고수 정보' ? `${styles.active}` : null}
      >
        <span>고수 정보</span>
      </li>
      <li
        onClick={e => {
          select(e);
          scroll(masterMedia);
        }}
        className={active === '사진/동영상' ? `${styles.active}` : null}
      >
        <span>사진/동영상</span>
      </li>
      <li
        onClick={() => {
          setActive('리뷰');
          scroll(masterReview);
        }}
        className={active === '리뷰' ? `${styles.active}` : null}
      >
        <span>{`리뷰 ${!reviewCounts[0].name ? 0 : reviewCounts.length}`}</span>
      </li>
      <li
        onClick={e => {
          select(e);
          scroll(masterInfo);
        }}
        className={active === '질문 답변' ? `${styles.active}` : null}
      >
        <span>질문 답변</span>
      </li>
    </ul>
  );
}

0개의 댓글