두번째 프로젝트 회고 - 밀리는 서재

Sulhwa Choi·2022년 11월 29일
3

📕 두번째 프로젝트 - [밀리는 서재]

  • 두번째 프로젝트 클론코딩 사이트로 '밀리의 서재' 사이트를 선정했다.

🎞️ 시연영상
https://www.youtube.com/watch?v=vOymkA7-0rU


⏰ 개발 기간

﹣ 2022.11.14~11.25

⚒️ 기술 스택

[프론트] - React, Javascript, Router, Sass
[백엔드] - Javascript, Express(Node.js), Mysql, dbmate(DB scheme 버전관리), jsonwebtoken(토큰 발행), bcryptjs(비밀번호 암호화),Axios

🙋🏻‍♀️ 내가 담당한 부분

  1. 도서 상세페이지 구현
  2. 서적 찜 기능 구현
  3. 서적 서재 담기 기능 구현
  4. 댓글 기능 구현
  5. 페이지 링크 복사 구현
  6. 내 서재 페이지 구현

🙌🏻 협업방식 - (트렐로)

트렐로를 이용해서 진행상황을 공유하고, 디스코드를 이용하여 매일 10시 회의를 하였습니다!

(1) 도서 상세페이지 구현

      {item.map(
        ({
          id,
          title,
          cover_img,
          toc,...
        }) => (
          <div className="wrapper" key={id}>
            <div className={css.BookContainer}>
              <img src={cover_img} alt="책 이미지" />
              <div className={css.BookInfo}>
                <div className={css.BookInfoContent}>
					...
                  {books_authors.map((prop, idx) => {
                    return <AuthorName key={idx} {...prop} />;
                  })}
                </div>
				...
		<Index key={toc.id} toc={toc} />
            {books_authors.map(author => {
              return <Author key={author.author_id} {...author} />;
            })}
            <Publisher key={publisher.id} publisher={publisher} />
            <Comments setBookInfoComments={setCommentArray} />
          </div>
        )
      )}

백엔드에서 해당 책의 정보가 담긴 데이터들을 가져왔다. map 함수를 돌려서 데이터를 넣어주었고, 해당하는 컴포넌트에 props를 이용해 데이터를 넘겼다. 배열데이터는 한번 더 map함수를 돌려 넘겨주었다.


(2) 서적 찜 기능 구현


  const [bookData, setBookData] = useState([]);
  const [likeCheck, setLikeCheck] = useState(false);

//찜 데이터 보내기
  const onFavorite = () => {
    fetch(`서버주소`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        authorization: localStorage.getItem('token'),
      },
      body: JSON.stringify({
        books_id: bookData[0].id,
      }),
    })
      .then(res => res.json())
      .then(res => {
        fetch(`서버주소`, {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json',
            authorization: localStorage.getItem('token'),
          },
        })
          .then(res => res.json())
          .then(data => {
            setLikeCheck(data);
          });
      });
  };

  //찜 데이터 삭제
  const delFavorite = () => {
    fetch(`서버주소`, {
      method: 'DELETE',
      headers: {
        'Content-Type': 'application/json',
        authorization: localStorage.getItem('token'),
      },
      body: JSON.stringify({
        books_id: bookData[0].id,
      }),
    })
      .then(res => res.json())
      .then(res => {
        fetch(`서버주소`, {
          headers: {
            'Content-Type': 'application/json',
            authorization: localStorage.getItem('token'),
          },
        })
          .then(res => res.json())
          .then(data => {
            setLikeCheck(data);
          });
      });
  };

찜부분은 fetch 를 많이해야만 했다..! 먼저 찜했을때 books_id 데이터를 보내고, 한번 더 클릭 시 삭제할 수 있도록 했다. 그리고 페이지에서 찜한 상품의 별은 노란색이 채워져 있어야해서 찜 값이 true일 시 적용 될 수 있도록 하였다. 물론 이 부분도 체크 데이터를 확인하기 위해 fetch를 사용했다.


(3) 서적 서재 담기 기능 구현


  //내 서재에 데이터 보내기
  const onMyShelf = () => {
    fetch(`서버주소`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        authorization: localStorage.getItem('token'),
      },
      body: JSON.stringify({
        books_id: bookData[0].id,
      }),
    });
  };

찜과 같이 서재 담기를 클릭 시 백으로 데이터를 전송하였다! 그 후 내서재 페이지에서 해당 책이 담긴 것을 확인 할 수 있다.


(4) 댓글 기능(추가, 삭제) 구현


----------댓글 추가

  const addComment = event => {
    fetch(`서버주소`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        authorization: localStorage.getItem('token'),
      },
      body: JSON.stringify({
        books_id: params.id,
        content: value.current.value,
      }),
    })
      .then(res => res.json())
      .then(res => {
        fetch(`서버주소`)
          .then(res => res.json())
          .then(data => {
            setComments(data.reviewInfo.reviewArray);
            setBookInfoComments(data.reviewInfo.reviewArray);
          });
      });
  };

// 댓글 데이터 가져오기
  useEffect(() => {
    fetch(`서버주소`)
      .then(res => res.json())
      .then(data => {
        setComments(data.reviewInfo.reviewArray);
        setBookInfoComments(data.reviewInfo.reviewArray);
      });
  });

댓글을 추가하면 백엔드로 데이터를 보내주고, 백에서 리뷰데이터를 가져와 보여주었다.

----------댓글 삭제

//comments.js
  const onRemove = review_id => {
    if (window.confirm('삭제 하시겠습니까?')) {
      fetch(`서버주소`, {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
          authorization: localStorage.getItem('token'),
        },
        body: JSON.stringify({
          review_id: review_id,
        }),
      })
        .then(res => res.json())
        .then(result => {
          setComments(comments.filter(props => props.review_id !== review_id));
        });
    }
  };

//comment.js
  {visible && (
       <button className={css.moreArea}
        onClick={() => onRemove(review_id)}>
              삭제하기
       </button>
   )}

삭제하기 버튼을 클릭하면 onRemove 함수가 실행 되고, filter메소드를 이용해서 해당 review_id와 다른 review_id들로 새로운 배열을 만들었다.


(5) 페이지 링크 복사 구현

  const copyUrl = () => {
    let url = '';
    let textarea = document.createElement('textarea');
    document.body.appendChild(textarea);
    url = window.document.location.href;
    textarea.value = url;
    textarea.select();
    document.execCommand('copy');
    document.body.removeChild(textarea);
    alert('복사가 완료되었습니다.');
  };

textarea의 value값에 지금 브라우저의 url을 넣어주고, document.execCommand('copy');로 클립보드에 복사하고, document.body.removeChild(textarea);로 필요없는 textarea를 제거했다.


(6) 내 서재 페이지 구현


useEffect(() => {
    fetch(`서버주소`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        authorization: localStorage.getItem('token'),
      },
    })
      .then(res => res.json())
      .then(data => {
        setBookDataList(data);
      });
  }, []);

 <div className={css.bookContainer}>
    <div className={css.bookBox}>
       <div className={css.imgBox}>
          {bookDataList.map((bookData, idx) => (
            <img key={idx} src={bookData.cover_img} alt="책 이미지" />
          ))}
        </div>
       <div className={css.bookSupport}></div>
    </div>
 </div>

백엔드에서 찜 데이터, 서재담기 한 책의 데이터 가져온 후, 찜에 해당하는 책, 내 책장에 해당하는 책들의 이미지를 넣어주었다.



👏 프로젝트 마치는 소감

﹣ 두번째 프로젝트여서 그런지 한결 수월했던 것 같았다. 백엔드와의 연결, 내 파트 코드 작성, 에러 해결 등등 프로젝트 하는 기간 동안 많이 전과 비교해 성장했음을 느낄 수 있었다! 마지막으로 2주동안 함께 열심히 해준 밀리는서재 팀원들 모두 수고하셨고 감사했습니다~!🙇🏻‍♀️

profile
개발 공부 중 〰️ ٩(๑•̀o•́๑)و ✨

2개의 댓글

comment-user-thumbnail
2022년 11월 29일

겸둥아 우리의 품으로 돌아와주겠어? 넘 잘만드렀쟈너 😖 ❤️

1개의 답글