마이 블로그 프로젝트 05-1 - 게시글 리스트 조회하기.

이유승·2023년 7월 18일
0
post-custom-banner

글을 작성하고 수정하는 기능이 완성되었으니, 다음은 글을 조회하는 기능을 구현해야 한다. 글을 조회하는 기능은 2가지로 나뉘어 진다. 글 목록을 조회하는 것과 글 내용을 조회하는 것.

내 프로젝트에서 목록 조회 컴포넌트와 내용 조회 컴포넌트는 상하관계를 갖지 않는다. 목록 조회 컴포넌트에서 글을 하나 클릭하면 내용 조회 컴포넌트로 이동되며, DB에 내용을 조회하는데 필요한 조건으로 사용할 문서의 id값을 url의 param으로 전달하는 방식으로 구현하였다.

<div className={styles.questionsitem} key={item.id} onClick={() => { navigate(`/questions/${item.id}`); }}>



1. 프론트 구성.

우선 페이지가 렌더링 되면, DB에서 게시글의 목록 데이터를 조회하여 배열 형식의 data 변수에 저장한다. 이후 map 함수를 이용하여 배열 렌더링 방식으로 글 목록을 출력하도록 구현하였다.

{data.map((item) => (
	<div className={styles.questionsitem} key={item.id} onClick={() => { navigate(`/questions/${item.id}`); }}>
		<div className={styles.questionsitemicon}></div>
		<div className={styles.questionsiteminfo1}>
		<div className={['default2_icon', `${item.type}_icon`].join(' ')} />
              {item.title}
		</div>
		<div className={styles.questionsiteminfo2}>
              {item.writer}
		</div>
		<div className={styles.questionsiteminfo3}>
              {item.time}
		</div>
	</div>
))}
  • key?
    만약 data 배열의 요소 중 하나에 변화가 생겼다고 하자. 자원 낭비를 방지하기 위해서는 변화가 생긴 부분만 다시 렌더링 해주면 된다. 그런데 이를 위해서는 배열 요소 각각을 식별할 '기준'이 필요하다. 각자 자신만의 '유니크'한 값이 존재해야하는 것이다. 데이터가 이미 유니크한 값을 가지고 있다면 그것을 사용하면 되고, 그게 없다면 map 함수에서 기본적으로 제공해주는 index를 적용해주면 된다. (다만 index 사용보다는 유니크한 값의 사용을 더 권장하고 있다. 배열 순서가 바뀔 경우에는 index가 꼬여서 문제가 발생하기 때문.)

다음은 조건 검색 기능의 구현이다. 내 프로젝트의 게시판은 각각의 글마다 어떤 종류의 글인지 나뉘어져있다. 게시글의 DB에 글의 종류가 저장되어 있는데, 프론트단에서 이를 이용해 조건 검색을 실행할 수 있도록 변수를 하나 만들고 이를 변환해줄 버튼을 생성하였다.

const [choiceType, setChoiceType] = useState('all');

 <div className={styles.pagenationbtu} onClick={() => { setChoiceType('all') }}>
       전체
 </div>
 <div className={styles.pagenationbtu} onClick={() => { setChoiceType('html') }}>
       HTML
 </div>
 <div className={styles.pagenationbtu} onClick={() => { setChoiceType('css') }}>
       CSS
 </div>
 <div className={styles.pagenationbtu} onClick={() => { setChoiceType('js') }}>
       JS
 </div>
 
 (...)
 



2. 조회 기능.

try {
    const querys = query(collectionRef, orderBy('createdTime', 'desc'));
    const querySnap = await getDocs(querys);
    const mappingData = querySnap.docs.map((doc) => ({
        id: doc.id,
        time: doc.data().createdTime.toDate().toLocaleString(),
        ...doc.data()
  	}));
	setData(mappingData);
}
	catch (error) {
	console.log(error);
};

파이어베이스에서 복수의 데이터를 가지고 오는데는 getDocs 함수를 사용한다. getDocs 함수는 가지고 올 데이터를 특정하는 query 함수를 인자로 사용하는데, 내가 구현한 기능은 전체 검색과 조건 검색의 2가지 상황이 존재하므로 조건문을 사용하여 서로 다른 query 함수를 사용하도록 분기를 나누어 작성하였다.

적절한 query 함수가 만들어지고, 이것이 getDocs 함수의 인자로 사용될 경우 파이어베이스는 조건에 맞는 데이터를 반환해준다. 그런데 이 경우 반환되는 데이터는 DB에 저장된 데이터만을 반환하지 않고 파이어베이스 객체형태로 데이터를 포함하여 반환해준다. 따라서 내가 필요한 데이터만을 따로 추출해야 한다.

반환된 데이터는 객체를 포함한 배열의 형태이다. 여기도 map 함수를 사용해야 한다. 프론트단에서 map 함수를 사용한 배열 렌더링에서 각 요소들은 유니크한 값을 가지고 있어야 하므로 글 데이터 이외에도 문서의 id값을 가져오도록 하고 작업이 완료된 데이터를 프론트로 보내주면 기능 구현 완료.

기능이 잘 동작하고 있다.

코드 평가.

평가 방법, 개인적인 코드 리뷰 및 Chat GPT 사용.

-> 오류를 처리하는 방법이 미흡. 에러 발생시 사용자에게 알려주는 피드백이 존재하지 않음.

-> 코드 유지보수의 효율성 떨어짐. 글을 조회하는 코드에서 중복되는 부분이 많음. (query 함수를 사용하는 부분만 조건문을 이용해 서로 다르게 대입되도록 해야하는데, 그 이외에 부분을 동일하게 작성함.)

-> 보안 낮음, 렌더링 최적화 필요. 글 목록을 조회하는 기능은 커스텀 hook을 따로 만들고 분리해서 사용하는 이유를 알아보는 차원에서 프론트단에 작성하였음. 나중에 생각해보니 이렇게되면 브라우저에서 백엔드 코드에 직접 접근이 가능해서 보안상 좋지 않고, 데이터를 가져와서 가공하는 동안 리액트에서 성능 저하가 일어날 수 있음.

profile
프론트엔드 개발자를 준비하고 있습니다.
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 7월 18일

훌륭한 글이네요. 감사합니다.

답글 달기