[JavaScript] Q&A renderTable함수 리팩토링

subb_ny·2023년 12월 5일
0
post-thumbnail

간단한 코드 설명
Q&A를 구현하기 위해 데이터를 받아서 table을 보여주는 코드이다. 질문과 답변을 데이터 값으로 매칭시켜서 보여주며, 페이지네이션을 구현했으며, 답변 status상태를 색으로 구분했다.

리팩토링 전 코드

function renderTable(page) {
  const tableBody = document.getElementById("tableBody");
  tableBody.innerHTML = "";

  for (
    let i = (page - 1) * itemsPerPage;
    i < page * itemsPerPage && i < totalItems;
    i++
  ) {
    const row = filteredQuestions[i];

    const matchingAnswer = filteredAnswers.find(
      (answer) => answer.ba_id === row.ba_id
    );

    if (itId == row.it_id) {
      const displayTitle =
        row.mb_id === currentUserId || producerAuthority === currentUserId
          ? row.qna_title
          : "비밀글 입니다.";
      const displayContent =
        row.mb_id === currentUserId || producerAuthority === currentUserId
          ? row.qna_content
          : "";

      const trTemplate = `
        <tr data-ba_id="${row.ba_id}">
            <td class="table_list_qna font_size ">${row.qna_status}</td>
            <td class="table_list_qna">
                <div class="qna_title">Q. ${displayTitle}</div>
                <div class="qna_content">${displayContent}</div>
            </td>
            <td class="table_list_qna nick_date">
                <div>${row.mb_id}</div>
                <div>${row.qna_date}</div>
            </td>
        </tr>`;
      tableBody.innerHTML += trTemplate;

     

     
  const statusCells = tableBody.querySelectorAll(".table_list_qna.font_size");

  statusCells.forEach((cell, index) => {
    const row = filteredQuestions[(page - 1) * 5 + index];

    if (row.qna_status === "답변대기") {
      cell.classList.add("font_color_wait");
    } else {
      cell.classList.add("font_color_complete");
    }
  });
      if (matchingAnswer) {
        let answerDisplayContent =
          row.mb_id === currentUserId || producerAuthority === currentUserId
            ? matchingAnswer.qna_answer_content
            : "비밀글에 대한 답변입니다.";

        const answerTemplate = `
            <tr class='table_tr_answer'>
                <td class='table_list'><img class='arrow-img' src='<?php echo G5_URL ?>/img/right-and-down.png/>' </td>
                <td class='table_list'><div class='qna_content'><span class='qna_strong'>A. </span> ${answerDisplayContent}</div></td>
                <td class='table_list nick_date'><div>${matchingAnswer.mb_id}</div><div>${matchingAnswer.qna_answer_date}</div></td>
            </tr>`; 
        tableBody.innerHTML += answerTemplate;
      }
    }
  }

  // 페이지네이션 로직
  const pagination = document.getElementById("pagination");
  pagination.innerHTML = "";
  if (currentPage > 1) {
    pagination.innerHTML +=
      '<button><img class="arrow" src="<?php echo G5_URL ?>/img/chevron.png/>"/></button>';
  } // > 생성 
  for (let i = 1; i <= totalPages; i++) {
    pagination.innerHTML += `<button id="page-${i}" class="page-button"token interpolation">${i})">${i}</button>`;
  } // 슷지 버튼 생성 
  if (currentPage < totalPages) {
    pagination.innerHTML +=
      '<button><img class="arrow" src="<?php echo G5_URL ?>/img/arrow.png/>"/></button>';
  }
} // < 생성 

🧩 리팩토링 후 코드

가장 먼저 생각해야할 것은 함수가 너무 길어 가독성이 떨어진다는 것이었다.
특히 template 문자열 코드가 함수안에 있으면 상당히 불편했다.
따라서 createQnaRowTemplate,createAnswerRowTemplate을 만들어 template을 return 해주었다.

또한 applyStatusColor를 함수로 묶은 이유는 중간에 코드 삽입이 되어 있어서 명시된 이름으로 기능을 한눈에 파악할 수 있으면 좋겠다고 생각이 되어 함수로 따로 빼주었다.

마지막으로 페이지네이션에서 버튼을 생성해주는 코드에서도 중복되는 부분이 있어 다른 부분은 인자로 넘겨주면 되겠다고 생각되어 함수로 만들었다. icon을 생성할 때는 icon인자만 다르게 넘겨주면 됐었는데, 중간에 숫자를 생성하는 부분은 icon이 없고 숫자만 생성되기 때문에 조건문에 따라서 return값을 다르게 넣어줬다. 근데 이 부분도 중복되는 부분이 있기에 최대한 간단화할 수 있는 방법을 고민중이다.

const  renderTable = (page) => {
  const tableBody = document.getElementById("tableBody");
  tableBody.innerHTML = ""; // 초기화 

  const user = "<?php echo($member['mb_id']); ?>";

  for (
    let i = (page - 1) * itemsPerPage;
    i < page * itemsPerPage && i < totalItems;
    i++
  ) {
    const row = filteredQuestions[i];
    const matchingAnswer = filteredAnswers.find(
      (answer) => answer.ba_id === row.ba_id
    );

    if (itId == row.it_id) {
      const displayTitle =
        row.mb_id === currentUserId || producerAuthority === currentUserId
          ? row.qna_title
          : "비밀글 입니다";
      const displayContent =
        row.mb_id === currentUserId || producerAuthority === currentUserId
          ? row.qna_content
          : "";

      const trTemplate = createQnaRowTemplate(
        row,
        displayTitle,
        displayContent
      );
      tableBody.innerHTML += trTemplate;

      applyStatusColor(tableBody, filteredQuestions, currentPage);

      if (matchingAnswer) {
        let answerDisplayContent =
          row.mb_id === currentUserId || producerAuthority === currentUserId
            ? matchingAnswer.qna_answer_content
            : "비밀글에 대한 답변입니다";
        const answerTemplate = createAnswerRowTemplate(
          matchingAnswer,
          answerDisplayContent
        );
        tableBody.innerHTML += answerTemplate;
      }
    }
  }

  // 페이지네이션 로직
  const pagination = document.getElementById("pagination");
  pagination.innerHTML = "";

  if (currentPage > 1) {
    console.log(currentPage);
    pagination.innerHTML += createPaginationButton(currentPage-1 , "chevron");
  }

  for (let i = 1; i <= totalPages; i++) {
    pagination.innerHTML += createPaginationButton(i);
  }

  if (currentPage < totalPages) {
    pagination.innerHTML += createPaginationButton(currentPage + 1, "arrow");
  }
}

함수로 분리

const createQnaRowTemplate = (row, displayTitle, displayContent) => {
  return `
        <tr data-ba_id="${row.ba_id}">
            <td class="table_list_qna font_size ">${row.qna_status}</td>
            <td class="table_list_qna">
                <div class="qna_title">Q. ${displayTitle}</div>
                <div class="qna_content">${displayContent}</div>
            </td>
            <td class="table_list_qna nick_date">
                <div>${row.mb_id}</div>
                <div>${row.qna_date}</div>
            </td>
        </tr>`;
}

const createAnswerRowTemplate = (matchingAnswer, answerDisplayContent) =>  {
  return `
        <tr class='table_tr_answer'>
            <td class='table_list'><img class='arrow-img' src='<?php echo G5_URL ?>/img/right-and-down.png/>' </td>
            <td class='table_list'><div class='qna_content'><span class='qna_strong'>A. </span>${answerDisplayContent}</div></td>
            <td class='table_list nick_date'><div>${matchingAnswer.mb_id}</div><div>${matchingAnswer.qna_answer_date}</div></td>
        </tr>`;
}

const applyStatusColor = (tableBody, filteredQuestions, page) =>  {
  const statusCells = tableBody.querySelectorAll(".table_list_qna.font_size");

  statusCells.forEach((cell, index) => {
    const row = filteredQuestions[(page - 1) * 5 + index];

    if (row.qna_status === "답변대기") {
      cell.classList.add("font_color_wait");
    } else {
      cell.classList.add("font_color_complete");
    }
  });
}

const createPaginationButton = (page, icon = "") =>  {
  const iconSrc = icon
    ? `<img class="arrow" src="<?php echo G5_URL ?>/img/${icon}.png"/>`
    : "";
   if (icon === "arrow" ||icon === "chevron" ) {
    return `<button id="page-${page}" class="page-button" token interpolation">${page})">${iconSrc}</button>`;
  } else {
    return `<button id="page-${page}" class="page-button" token interpolation">${page})">${iconSrc}${page}</button>`;
  }
}

0개의 댓글