이 영역을 누르면 첫 페이지로 이동
천천히 꾸준히 조용히 블로그의 첫 페이지로 이동

천천히 꾸준히 조용히

페이지 맨 위로 올라가기

천천히 꾸준히 조용히

천천히 꾸준히 조용히.. i3months 블로그

[Vue] map 함수와 Vue3의 반응형 시스템

  • 2023.11.16 15:48
  • 💡 솔루션
반응형

 

 

 

서버에서 데이터를 받아오고, 받아온 데이터를 v-for 반복문을 사용해서 렌더링한다고 생각해보자. 

 

 

        <thead v-for="(subject, index) in subjects" :key="index" class="table-element">
          <tr>
            <th class="text-left table-header">
              <div>                
                <span>{{ subject.subject_no }}</span>

                <!-- <span class="text-weight-bold">성별</span>                
                <span v-if="subject.gender == 'Female'">여성</span>
                <span v-if="subject.gender == 'Male'">남성</span>
                <span v-if="subject.gender == ''"></span>

                <span class="text-weight-bold">연령(개월)</span>
                <span>{{ subject.age_month }}</span> -->
              </div>              
            </th>                        
          </tr>
          <tr>
            <th class="text-left table-header">
              <div class="th-container">
                <div>
                  <span class="text-weight-bold">성별</span>                
                  <span v-if="subject.gender == 'Female'">여성</span>
                  <span v-if="subject.gender == 'Male'">남성</span>
                </div>                                     
                <q-btn
                  size="xs"
                  padding="xs"
                  color="blue"
                  icon="edit"
                  @click="editSubject(subject, index)"
                />
              </div>              
            </th>
            <td class="text-center flex-container">              
              <span class="q-gutter-sm checkbox-list">
                <q-checkbox dense v-model="subject.a" color="blue" label="a" :disable="subject.resultModel.value !== 'new'"/>
                <q-checkbox dense v-model="subject.b" color="blue" label="b" :disable="subject.resultModel.value !== 'new'"/>
                <q-checkbox dense v-model="subject.c" color="blue" label="c" :disable="subject.resultModel.value !== 'new'"/>
                <q-checkbox dense v-model="subject.d" color="blue" label="d" :disable="subject.resultModel.value !== 'new'"/>                
              </span>
                    
              <span class="button-list">
                <q-btn color="blue" label="검사 시작 " :disable="subject.resultModel.value !== 'new'" @click="startNewExamine(subject)"/>
                <q-btn color="blue" label="재검사" :disable="subject.resultModel.value == 'new' || subject.resultModel.value == ''"/>
                <q-btn color="blue" label="결과 보기" :disable="subject.resultModel.value == 'new' || subject.resultModel.value == ''" @click="showResult(subject)"/>
              </span>
            </td>    
          </tr>
          <tr class="tr-margin"></tr>   
        </thead>

 

 

 

 

 

각 subject에 대해 watch 등 비즈니스 로직을 추가하려면 서버로부터 subjects를 받아올 때 map, forEach 등 반복문을 사용해 각각의 subject에 로직을 추가하는 방식으로 작업하면 된다.

 

여기서 map을 사용할 때는 주의할 점이 하나 더 있다.

Vue3 에서는 reactive 또는 ref로 감싼 객체만이 반응형으로 동작해 데이터의 변경을 감지하고 해당 Vue 컴포넌트를 동적으로 업데이트 할 수 있다.

 

(ref는 단일 값을 반응형으로 만들 때 사용하고 reactive는 객체를 반응형으로 만들 때 사용한다. ref는 .value로 값에 접근할 수 있고 reactive는 일반 객체처럼 직접 값에 접근할 수 있다)

 

 

function getAllSubject() {
  api.get('/subject/get-all-subject')
      .then(response => {        
        subjects.value = response.data.map(subject => {

          watch(() => subject.resultModel, (newValue) => {
            if(newValue == 'new') {
              subject.a = false;
              subject.b = false;
              subject.c = false;
              subject.d = false;
            }

            if(newValue != 'new') {
              api.get('/subject/get-result', {
                params: {
                  subject_no: subject.subject_no,
                  examine_date: subject.resultModel.value
                }
              })
              .then(response => {
                subject.a = response.data.selected.aa;
                subject.b = response.data.selected.bb;
                subject.c = response.data.selected.cc;
                subject.d = response.data.selected.dd;                                                                                
              })
              .catch(error => {
                console.error("결과 불러오기 오류", error);
              })
            }

          });

          if(subject.result_list && subject.result_list.length > 0) {
            subject.result_list.sort((a, b) => {
              const formatA = a.replace(/-/g, "/").replace(/(\d{4})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})/, "$1/$2/$3 $4:$5:$6");
              const formatB = b.replace(/-/g, "/").replace(/(\d{4})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})/, "$1/$2/$3 $4:$5:$6");
              return new Date(formatB) - new Date(formatA);
            });
          }
          return {
            ...subject,
            result_list: subject.result_list.sort((a, b) => new Date(b) - new Date(a)),
            resultModel: {
              value: '',
              label: '',
            },
            a: false,
            b: false,
            c: false,
            d: false,
          }
        })        
      })

      .catch(error => {
        console.error("subject/get-all-subject 오류", error)
    })
}

 

 

 

이렇게 map 함수를 사용해서 각 subject에 watch를 추가하면 제대로 작동할까?

 

자바스크립트의 map 함수는 배열의 각 요소에 대해 주어진 함수를 실행하고 그 결과를 새로운 배열으로 반환하는 함수로 원본 배열을 변경하지 않고 각 요소에 대해 적용된 함수의 결과로 새로운 배열을 생성하는 함수이다.

 

위의 예시에서는 map 함수 내에서 새로 생성된 객체들이 Vue의 반응형 시스템에 추적되지 않는다.

따라서 map 함수 내에서 새롭게 생성하는 각 객체들을 reactive로 명시적으로 감싸 반응형으로 만들어야 한다.

 

함수를 수정해보자.

 

 

function getAllSubject() {
  api.get('/subject/get-all-subject')
      .then(response => {        
        subjects.value = response.data.map(subjectData => {
          const subject = reactive({
          ...subjectData,
          resultModel: {
            value: '',
            label: ''
          },
          a: false,
          b: false,
          c: false,
          d: false,
        });

          watch(() => subject.resultModel.value, (newValue) => {            
            if(newValue == 'new') {
              subject.a = false;
              subject.b = false;
              subject.c = false;
              subject.d = false;
            }

            if(newValue != 'new') {
              api.get('/subject/get-result', {
                params: {
                  subject_no: subject.subject_no,
                  examine_date: subject.resultModel.value
                }
              })
              .then(response => {
                subject.a = response.data.selected.aa;
                subject.b = response.data.selected.bb;
                subject.c = response.data.selected.cc;
                subject.d = response.data.selected.dd;                
              })
              .catch(error => {
                console.error("결과 불러오기 오류", error);
              })
            }

          });

          if(subject.result_list && subject.result_list.length > 0) {
            subject.result_list.sort((a, b) => {
              const formatA = a.replace(/-/g, "/").replace(/(\d{4})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})/, "$1/$2/$3 $4:$5:$6");
              const formatB = b.replace(/-/g, "/").replace(/(\d{4})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})/, "$1/$2/$3 $4:$5:$6");
              return new Date(formatB) - new Date(formatA);
            });
          }
          return subject;
        })        
      })

      .catch(error => {
        console.error("subject/get-profile 오류", error)
    })
}

 

 

 

subjectData 객체는 api 응답으로부터 받은 원시 데이터를 가지고 있고, 이 데이터를 바탕으로 새로운 반응형 객체인 subject를 정의한다,

 

watch 함수로 데이터의 변화를 감지하고 지정된 콜백 함수를 실행시킨다.

예시에서는 resultModel.value가 변경될 때 마다 콜백 함수가 호출되고, subject의 다른 속성 값을 변경해 반응형을 구현한다.

 

요점은 map 함수 내부에서 reactive 객체를 반환한다는 점이다.

map 함수 사용 시 컴포넌트를 반응형으로 반환하는 부분을 빼먹는 경우가 많으니.. 주의하자.

 

 

반응형
저작자표시 (새창열림)

'💡 솔루션' 카테고리의 다른 글

[SQL Server] 지원하지 않는 TLS 버전 설정  (1) 2024.06.05
대용량 파일 업로드 처리 (30GB)  (1) 2023.12.03
[JavaScript] Shadow DOM 다루기  (0) 2023.11.22
[Git] Git 협업 시 충돌 해결  (1) 2023.11.14
디렉토리 구조 탐색과 이미지 메타데이터 저장  (0) 2023.09.17

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • 대용량 파일 업로드 처리 (30GB)

    대용량 파일 업로드 처리 (30GB)

    2023.12.03
  • [JavaScript] Shadow DOM 다루기

    [JavaScript] Shadow DOM 다루기

    2023.11.22
  • [Git] Git 협업 시 충돌 해결

    [Git] Git 협업 시 충돌 해결

    2023.11.14
  • 디렉토리 구조 탐색과 이미지 메타데이터 저장

    디렉토리 구조 탐색과 이미지 메타데이터 저장

    2023.09.17
다른 글 더 둘러보기

정보

천천히 꾸준히 조용히 블로그의 첫 페이지로 이동

천천히 꾸준히 조용히

  • 천천히 꾸준히 조용히의 첫 페이지로 이동

검색

방문자

  • 전체 방문자
  • 오늘
  • 어제

카테고리

  • 분류 전체보기 (675) N
    • Algorithm (205)
      • Data Structure (5)
      • Theory && Tip (33)
      • Baekjoon (166)
      • ALGOSPOT (1)
    • Spring (123)
      • Spring (28)
      • Spring Web MVC (20)
      • Spring Database (14)
      • Spring Boot (6)
      • Spring 3.1 (11)
      • Spring Batch (6)
      • Spring Security (16)
      • JPA (12)
      • Spring Data JPA (5)
      • QueryDSL (4)
      • eGovFramework (1)
    • Programming Language (74)
      • C (25)
      • C++ (12)
      • Java (19)
      • JavaScript (15)
      • Python (1)
      • PHP (2)
    • Computer Science (142)
      • Machine Learning (38)
      • Operating System (18)
      • Computer Network (28)
      • System Programming (22)
      • Universial Programming Lang.. (8)
      • Computer Architecture (4)
      • Compiler Design (11)
      • Computer Security (13)
    • Database (21)
      • Database (7)
      • MySQL (3)
      • Oracle (3)
      • Redis (5)
      • Elasticsearch (3)
    • DevOps (20)
      • Docker && Kubernetes (8)
      • Jenkins (4)
      • Amazon Web Service (8)
    • Mobile (28)
      • Android (21)
      • Flutter (7)
    • 💡 솔루션 (17)
    • 👥 모각코 (8)
    • 💬 기록 (7) N
    • 📚 공부 (5)
    • -------------- (25)

최근 글

나의 외부 링크

메뉴

  • 홈
반응형

정보

i3months의 천천히 꾸준히 조용히

천천히 꾸준히 조용히

i3months

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © i3months.

티스토리툴바