본문 바로가기

Vue.js

[Udemy Vue 완벽가이드 Section13] 176. 감시자(Watcher)로 매개변수 데이터 업데이트하기

라우트 매개변수는 유용하지만, 사용하기 까다로울 수도 있다.

애플리케이션에서 라우트 매개변수 활용 시, 발생할 수 있는 문제 상황을 하나 만들어 보자.

 

 

# 라우트 매개변수 활용 시, 문제상황

TeamMembers.vue파일의 컴포넌트는 라우트를 매개변수와 함께 로드한다.

그런데 모종의 이유로 router-link태그를 사용해야 한다고 치자.

텍스트는 'Go to Team 2'로 설정하고, 링크는 항상 '/teams/t2'로 가도록 연결하자.

<router-link to="/teams/t2">Go to Team 2</router-link>

 

어디까지나 만들어낸 상황이지만, 이런 일이 있을 수도 있다.

애플리케이션에서 특정 매개변수에 대해 로드된 페이지가 있는데 바로 그 페이지에서 매개변수의 다른 값에 대한 페이지로 가야할 수도 있다.

지금 만든 상황이 그런 경우를 가정한 것.

 

파일을 저장하고 나면, 하단에 'Go to Team 2' 링크가 생긴다.

2팀 페이지에서는 'Go to Team 2'링크 클릭 시, 변화가 없다.

하지만 1팀 페이지에서 클릭했을 때도 바뀌는게 없다.

 

## URL 변경에도 그대로인 화면

이게 위에서 말한 문제 상황이다.

동적 매개변수로 로드된 페이지에서 다른 페이지로 가고 싶으면, 즉, 매개변수의 다른 값을 가진 페이지로 간다면, Vue 컴포넌트를 가진 사실상 같은 페이지로 이동 시 문제가 생긴다.

 

여기서 알아야하는 것은 1팀의 URL은 localhost:8080/teams/t1인데 'Go to Team 2'를 누르면 URL이 '/teams/t2'로 바뀐다는 것.

URL은 바뀌는데 화면에 표시되는 데이터는 그대로라면, 버그인걸까?

→ 그렇지 않다. 이는 의도된 동작이다.

페이지 탐색 시, Vue 라우터는 로드된 컴포넌트를 파기하고 새로 구축하지 않는다.

왜냐하면 URL이 바뀔때마다 파기하고 새로 구축하기보다 캐시에 저장하는 것이 훨씬 효율적이다.

거기서 문제가 발생한다.

 

TeamMembers.vue 데이터는 created()로 로드하는데 created()호출은 컴포넌트가 생성될(created) 때 일어난다.

Vue라우터는 URL이 바뀌었다고 컴포넌트를 파기하고 새로 생성하지 않는다. 따라서 URL이 바뀌더라도 created()가 다시 실행되지 않는다.

그래서 애플리케이션 페이지에서 다른 데이터, 새로운 매개변수를 가진 페이지를 로드하고 싶어도 Vue라우터는 기본 설정상 반응하지 않는다. 반응하도록 고쳐야한다.

어떻게하면 URL 변화에 적절히 반응하게 할 수 있을까?

 

# URL 변경에 따른 새 페이지 로드방법

URL이 바뀌면 다른 중요한 요소도 바뀐다. 그 중요한 요소는 바로 $route 프로퍼티이다.

로드한 라우트에 대한 최신 정보를 담고 있는데다가, URL이 바뀌면 업데이트되는 프로퍼티이다.

따라서 $route 객체는 언제나 최신 매개변수를 포함한다.($route.params)

그렇게 때문에 여기에 감시자(watcher)를 추가하면 여기 내장된 프로피티인 $route가 변하는 것을 감시할 수 있다.

route가 바뀔 때마다 이 감시자가 실행된다.

따라서 $route에는 newRoute를 넣자.

이제 $route(newRoute)에서 아래 created함수 내부의 로직을 다시 실행하면 된다.

created() {
  const teamId = this.$route.params.teamId;
  const selectedTeam = this.teams.find((team) => team.id === teamId);
  const members = selectedTeam.members;
  const selectedMembers = [];
  for (const member of members) {
    const selectedUser = this.users.find((user) => user.id === member);
    selectedMembers.push(selectedUser);
  }
  this.members = selectedMembers;
  this.teamName = selectedTeam.name;
},

 

코드를 복제하는 대신, methods를 추가하고 loadTeamMembers를 만들고 그 안에 로직 코드를 두자. 그 다음에 created()에 직접 loadTeamMembers를 호출하고, watch에도 loadTeamMembers를 호출한다.

 

methods: {
 loadTeamMembers(route) {
    const teamId = route.params.teamId;
    const selectedTeam = this.teams.find((team) => team.id === teamId);
    const members = selectedTeam.members;
    const selectedMembers = [];
    for (const member of members) {
      const selectedUser = this.users.find((user) => user.id === member);
      selectedMembers.push(selectedUser);
    }
    this.members = selectedMembers;
    this.teamName = selectedTeam.name;
 },
},
created(){
  this.loadTeamMembers(this.$route);
},
watch: {
 $route(newRoute) {
   this.loadTeamMembers(newRoute);
 }
}

 

이제 컴포넌트가 생성될 때만 팀 멤버를 로드하는 메서드(loadTeamMembers)를 로드하고 실행하는게 아니라, 라우트가 바뀌었을 때도 똑같은 작업을 해줄 거다.

 

또 추가하고 싶은 부분은 this.loadTeamMembers에 newRoute를 인수로 전달한다. 

created()에서 this.loadTeamMembers를 호출할 때도 this.$route를 전달하자.

$route 객체를 인수로 전달하고, 메서드에도 추가해서 loadTeamMembers에 route 객체를 두었다. this.$route는 route로 교체하자.

필수 작업은 아니지만 methods의 라우트를 외부에서 쓰려면 이렇게 해야하고, 메서드 호출 시 this.$route를 인수로 전달할 수 있다.

 

이제 파일을 저장하고 새로고침을 하면 팀별 페이지의 링크가 제 기능을 하고 'Go to Team 2' 링크를 클릭하면 라우트에 생기는 변화를 감시(watch) 중이라 페이지도 업데이트된다.

 

URL에 따라 페이지 새로고침을 구현하는 방법 한가지를 배웠다.

확실히 잘 작동하는 방법이지만, 수많은 방법 중 하나일 뿐이다.

이 경우에도 나름의 문제가 있어서 TeamMembers 컴포넌트 사용에 뭔가 불편한 점이 있을 수 있다.

 

** 출처: 모든 내용은 Udemy Vue-완벽가이드 강의를 기반으로 작성하였습니다.