내일배움캠프 React_7기 TIL - 4. 미니프로젝트 Update, Delete 기능 구현 관련 트러블슈팅

·2024년 10월 4일
0

Create와 Read기능은 순탄하게 잘 진행이 되었는데, U, D 기능에서 문제가 생겼다.

Update 관련 문제

선택된 멤버의 정보만을 업데이트 할 수 있도록 기능 구현

이건 트러블은 아니였고, 구현해야 할 기능이였으나 기록해보자면
snapshot.key 로 받아온 멤버 데이터의 고유 ID를 사용하여 접근하고 Update하면 된다고 생각했다.

데이터의 고유 ID를 한 js 파일에서 선언하고, 다른 js파일에서도 접근할 수 있도록 하고 싶었다.

window.변수

변수는 파일 단위의 스코프인 전역 변수만 알고 있었는데, 이번에 브라우저 전역 객체window 변수를 배우게 되었다. window 객체에 변수를 추가하면, 그 변수가 브라우저에서 실행되는 모든 스크립트에 공유된다고 볼 수 있다.
나는 2개의 js 파일 내에서 memberID의 값을 공유하고자 했기에 사용하였다.

teamMate.js

window.currentMemberId = null; //멤버데이터 ID값 저장 전역변수
...

function openModal(...) {
  window.currentMemberId = memberId; // 선택된 멤버의 ID 저장
  
...

modalScript.js

saveMember(name, mbti, blog, intro, description, imgUrl, window.currentMemberId);

이렇게 teamMate.js 에서 값을 넣어준 window.currentMemberId 변수에modalScript.js가 접근하여 값을 사용할 수 있었다.

saveMember 함수가 window.currentMemberId을 인자로 받고, 이 currentMemberId가 들어 있을 시 Update를, 비어 있을 때 Create를 하도록 했다.

const saveMember = (..., currentMemberId) => {
  if (currentMemberId) {
    // 수정 (memberId 있을 때)
    memberFormDb.child(currentMemberId).once("value").then((snapshot) => {
      const existingData = snapshot.val(); // 기존 데이터 가져오기
      const updatedData = {
        ...
      };
      
      return memberFormDb.child(currentMemberId).update(updatedData);
    }).then(() => {
      console.log("멤버 정보 수정 완료");
 
      location.reload(); 

    }).catch((error) => {
      console.log("수정 중 오류: ", error);
    });
  } else {
    // 새로운 멤버 등록
    var newMember = memberFormDb.push();
    newMember.set({
      ...
    }).then(() => {
      console.log("새로운 멤버 등록 완료");
      
    }).catch((error) => {
      console.log("등록 중 오류: ", error);
    });
  }
};

사실 데이터의 key값을 전역변수로 뺀 거라서 보안 상의 문제가 가장 걱정이였다.
함수의 매개변수로 전달하거나,클로저 또는 모듈 패턴을 활용하는 방법이 있다고 하는데 다음에는 다르게 시도해봐야겠다. (클로저가 뭔지 아직 모름. 공부하자...)
Redux로 전역 상태 관리를 해 본 적 있지만, 이번에는 라이브러리 없이 window 객체로 전역 데이터를 관리(?)하는 방법을 새로 배웠다! (하지만 사용에 조심해야 해서 다음엔 이런 사용을 지양하고자 한다.)

멤버 카드를 작성 후, 또 새로운 카드를 작성하려고 할 때 이미지의 URL이 이전에 작성했던 이미지의 URL이 그대로 들어가는 문제

등록 후 전역변수로 사용한 imgUrl을 다시 비워주지 않아 생긴 문제로 추측되었다.
그래서, SaveMember 함수가 실행 후 imgUrl을 비우니 해결되었다.

Delete 관련 문제

여러개의 카드를 클릭하면, eventLisnter('click')가 중복되어 클릭한 카드를 모두 삭제해버리는 문제.

중복 이벤트 리스너 처리...를 제대로 할 줄 몰랐던 점 반성합니다. 너무 주먹구구식 코드를 짰나보다.

문제 원인:
모달을 열 때마다 addEventListener로 새로운 이벤트 리스너가 등록됨.
이전에 등록된 리스너를 제거하지 않아서 클릭할 때 중복으로 실행됨.

이것도 해결 방법이 어려운 건 아니였다.

// 오류 원인이 됐던 코드
cardDiv.addEventListener("click", (event) => {
    modal_1.style.display = "flex"; // 모달 열기
    // ... 모달 내용 설정 ...
});

위 코드에서는 카드가 클릭될 때마다 모달을 여는 동시에 새로운 클릭 이벤트 리스너가 추가되었다. 이로 인해 클릭 이벤트가 발생할 때마다 이전에 등록된 이벤트 리스너들이 남아 있었다.

// 수정한 코드
cardDiv.addEventListener("click", () => {
    openModal(memberId, imgUrl, name, mbti, blog, intro, description, cardDiv);
});
openModal(...){
	yesBtn.removeEventListener("click", handleDelete);
    yesBtn.addEventListener("click", handleDelete);
}

이벤트 리스너를 중복으로 등록하지 않도록 removeEventListener를 사용하여 이전 리스너를 제거했다. 각 카드에서 클릭 이벤트가 발생할 때마다 handleDelete 함수가 중복으로 등록되는 것을 방지하고, 가독성을 높이기 위해 다음과 같이 수정했다.

이벤트 리스너가 생성되고 종료되어야 할 타이밍을 잘 파악하고... 꼭 remove하자.

삭제 알럿이 2번씩 뜬다...?

.remove() 함수에서 자체적으로 삭제되었다는 alret을 줬나보다... 근데 내가 한번 더 alret을 함. 그래서 2번 나옴. ^^

+ 말풍선 만들기 css

css를 잡다가 말풍선 만드는 방법을 다시 정리했다.

#menu1 {
  display: none; 
  position: absolute;
  top: 45px; 
  right: 17px; 
  background-color: white; 
  padding: 10px; 
  box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); 
  border-radius: 10px; 
  font-size: 14px; 
  display: flex; 
  flex-direction: column; 
  width: 70px; /* 원하는 너비로 조정 */
  border: 1px solid #ddd; /* 회색 테두리 */
}

#menu1::after {
  content: "";
  position: absolute;
  top: -19px; /* 삼각형 위치 조정 */
  right: 21px; /* 위치 조정 */
  border-width: 10px; /* 삼각형 크기 */
  border-style: solid;
  border-color: transparent transparent white transparent; /* 아래로 향하는 흰색 삼각형 */
  display: block;
}

#menu1::before {
  content: "";
  position: absolute;
  top: -21px; /* 회색 테두리 삼각형이 약간 더 위로 */
  right: 20px; /* 위치를 흰색 삼각형과 맞춤 */
  border-width: 11px; /* 회색 테두리 크기를 조금 더 크게 */
  border-style: solid;
  border-color: transparent transparent #ddd transparent; /* 아래로 향하는 회색 삼각형 */
  display: block;
}

::after로 만들어놓은 삼각형이 이미 border을 설정해놓은 거라, 말풍선 바디 부분이랑 어떻게 같이 border을 주는거지... 하고 고민하고 있었는데
알고보니 뒤에 조금 더 큰 border color의 삼각형을 만들고 겹쳐서 border을 준 것 처럼 만드는 것이였다.

음 앞으론 더 쉽게 만들겠군.

+ ::file-selector-button

type="file"인 input의 css는 어찌 넣는 건가. 했는데

input[type="file"] {
  height: fit-content;
  border:none;
}
input[type="file"]::file-selector-button {
  width: 80px;
  height: 30px;
  background: #fff;
  border: 1px solid rgb(77, 77, 77);
  border-radius: 5px;
  cursor: pointer;
  margin-right :13px ;
}

input[type="file"]::file-selector-button:hover {
  background: #212529;
  color: #fff;
}

file-selector-button으로 "파일 선택" 부분 css를 잡을 수 있었다. 새로 안 사실.

css적용 본은 이러하다.

오늘 드디어 Firebase Realtime DB + Storage로 CRUD 구현을 끝마쳐 후련하다.

profile
내배캠 React_7기 이수중

0개의 댓글

관련 채용 정보