브라우저 뒤로가기 버튼 클릭 시 vue-router query 추가하기

Maliethy·2023년 2월 4일
0

vuejs

목록 보기
2/3

1. issue

조건: 테이블이 있는 메인 페이지(이하 Main)와 테이블에 담긴 리스트를 클릭하면 해당 리스트에 대한 상세페이지(이하 Detail)가 있다.

Main과 Detail 페이지의 라우터 구조는 다음과 같다.

import Store from '@/views/Desktop/Store';
import StoreAdjustment from '@/views/Desktop/Store/Adjustment';
import StoreAdjustmentDetail from '@/views/Desktop/Store/AdjustmentDetail';

export default [{
  path: 'store-adjustment',
  name: routeName.STORE_ADJUSTMENT,
  component: Store,
  redirect: {
    name: routeName.STORE_ADJUSTMENT,
  },
  children: [
    {
      path: 'list',
      name: routeName.STORE_ADJUSTMENT,
      component: StoreAdjustment,
    },
    {
      path: 'list/:storeId/detail',
      name: routeName.STORE_ADJUSTMENT_DETAIL,
      component: StoreAdjustmentDetail,
    },
  ],
}];

Main 페이지의 조회기간에서 사용자가 선택한 월 또는 기본 선택값(이하 selectedMonth)을 예를 들어 테이블의 a 리스트 클릭 시 해당 a리스트에 대한 Detail 페이지갈 때 query로 담아서 보낸다. Detail 페이지에서 브라우저 뒤로가기 버튼 클릭 시 selectedMonth를 기억하고 있다가 Main 페이지의 url query에 넣어주어야하는 이슈이다. 다음은 해당 요구사항을 workflow로 구체화해본 것이다.

workflow

  1. 처음 페이지 진입 시 default 요일을 query string으로 넣어주기

  2. 사용자가 조회기간을 선택하면 query string을 해당 선택 월로 변경하기, 테이블 리스트 하나를 클릭해 상세페이지로 넘어가기

  3. 상세페이지에서 브라우저 뒤로가기 버튼 클릭하기

  4. 사용자가 기존에 선택했던 12월이 query string과 조회기간 input에 모두 적용되도록 하기

solution

처음에는 sesstion Storage에 사용자가 선택한 요일을 저장해 넘겨주는 방식으로 수정했는데, 리뷰어로부터 이는 웹의 강점을 살리지 못하는 방식이라는 PR 리뷰를 받았다. 그래서 다시 url에 query string으로 해당 요일 값을 넣어주는 방식으로 작업 방향을 수정했다.

참고로 web의 강점, query string을 사용하는 것이 중요한 이유는 permalink를 만들 수 있기 때문이다. 백오피스의 경우 A사용자가 자신이 12월로 검색한 결과를 B사용자와 공유하고 싶을 때 유용하다.

vue-router navigation guard 사용하며 겪은 이슈는 다음과 같다.
다음과 같은 폴더구조에서 예컨대 '@/views/Desktop/Store/Adjustment/Controller'에서는 beforeRouteEnter가 작동하지 않는다.

@/views/Desktop/Store/Adjustment 에서 beforeRouteEnter를 사용해야 한다.
이는 네비게이션 가드 - 전체 네비게이션 시나리오에 따르면 beforeRouteEnter는 컴포넌트가 새로 생성되어 DOM에 부착되거나(라이프사이클의 mounted에 해당) 새로 갱신될 때(updated) 작동하기 때문이다.

전체 네비게이션 시나리오

  • 네비게이션이 트리거됨.
  • 비활성화될 컴포넌트에서 가드를 호출.
  • 전역 beforeEach 가드 호출.
  • 재사용되는 컴포넌트에서 beforeRouteUpdate 가드 호출. (2.2 이상)
  • 라우트 설정에서 beforeEnter 호출.
  • 비동기 라우트 컴포넌트 해결.
  • 활성화된 컴포넌트에서 beforeRouteEnter 호출. // 이 부분!!
  • 전역 beforeResolve 가드 호출. (2.5이상)
  • 네비게이션 완료.
  • 전역 afterEach 훅 호출.
  • DOM 갱신 트리거 됨.
  • 인스턴스화 된 인스턴스들의 beforeRouteEnter가드에서 next에 전달 된 콜백을 호출합니다.

beforeRouteEnter가드는 다음과 같이 사용했다.

<template>
  <div class="store-adjustment-wrapper">
    <Controller></Controller>
    <StoreAdjustmentList></StoreAdjustmentList>
  </div>
</template>

<script>
import Controller from '@/views/Desktop/Store/Adjustment/Controller';
import StoreAdjustmentList from '@/views/Desktop/Store/Adjustment/StoreAdjustmentList';

export default {
  name: 'StoreAdjustment',
  beforeRouteEnter(to, from, next) {
    const { selectedMonth: fromSelectedMonth } = from.query;
    const { selectedMonth: toSelectedMonth } = to.query;

    // storeAdjustmentDetail page에서 브라우저 뒤로가기 버튼 클릭 시 사용자가 선택한 조회기간으로 설정하기
    if (from.name === routeName.STORE_ADJUSTMENT_DETAIL
          && fromSelectedMonth !== toSelectedMonth
    ) {
      next({
        ...to,
        query: {
          selectedMonth: fromSelectedMonth,
        },
      });
    }

// 처음 Main 페이지 진입 시
    if (!toSelectedMonth) {
      const selectedMonth = format(beforeMonths(today, subDay), dateFormat);

      next({
        ...to,
        query: {
          selectedMonth,
        },
      });
    }

// 그밖의 모든 경우
    next();
  },
};
</script>

그러나 이는 결과적으로 불필요했는데, 브라우저 뒤로가기 버튼 클릭 시에 메인 페이지 url에 query string이 남아있기 때문에 다음과 같이selectedMonthQuery로 query값이 있는지 확인 후 있으면 vuex에 넣어주고 없다면 임의의 값(this.maxMonth)를 만들어 넣어주는 방식으로 해결했다.


    /**
     * 상점정산 페이지 엔트리 포인트
     */
    async init() {


      // 조회기간(필수 query 값)/검색어(옵션 query 값)의 경우 query stirng에 있는 값으로 동기화하기
      // 1. detail page에서 목록보기 button click으로 다시 돌아온 경우
      // 2. detail page에서 브라우저 뒤로가기 버튼 클릭 시
      // 3. 해당 값의 query string이 있는 url로 직접 접근 시
      const selectedMonthQuery = this.$route.query.selectedMonth;
      const searchWordQuery = this.$route.query.searchWord || '';

      this.selectedMonth = selectedMonthQuery || this.maxMonth;
      if (!selectedMonthQuery) {
        this.$router.replace({
          ...this.$route,
          query: {
            selectedMonth: this.selectedMonth,
          },
        }).catch(() => {});
      }

      // 4. 필터 기본 설정(vuex 초기 설정하기)
      await this.setFilterOptions({
        selectedMonth: this.selectedMonth,
        searchWord: {
          value: searchWordQuery,
          //   field: this.searchFieldType,
        },
      });

}

사용자가 data-picker를 변경할 때마다 query string을 바꾸는 부분은 다음과 router.replace를 사용해 해결했다.

//변경 버튼 클릭 시 호출되는 method
    handleClickPickerSubmit() {
      this.setFilterOptions({
        selectedMonth: this.selectedMonth,
      });
      this.modal = false;
      this.$router.replace({
        query: {
          ...this.$route.query,
          selectedMonth: this.selectedMonth,
        },
      })
        .catch(() => {});
    },

p.s. 뒤로 가기 버튼을 클릭해도 vuex는 새로고침되지 않는 것을 새로 알게 되었다...

profile
바꿀 수 있는 것에 주목하자

0개의 댓글