제 2장 SPA로 작동하도록 라우터 개선

업데이트: Link

2. SPA로 작동하도록 라우터 개선

나만의 라우터 만들기 시리즈 의 4부 중 2부
알렉스 조버 모랄레스씀

이 시점에서 라우터는 window.location 강제 리로드를 수행하는 새 경로를 직접 할당하기 때문에 단일 페이지 앱(SPA) 라우터로 작동하지 않습니다.

라우터를 SPA 라우터로 사용하도록 조정하기 위해 무엇을 해야 하는지 봅시다.

해시 및 HTML5 기록

강제 리로드를 처리하기 위해 모드 라고 하는 두 가지 대안이 있습니다.

  • hash : 해시를 사용 하여 SPA와 다른 경로인 프래그먼트 식별자 를 정의 합니다.
    이렇게 하면 프런트 엔드 라우팅이 #마크 에서 시작됩니다.
    이것이 전통적인 방법입니다. 예: https://example.io/#/home
  • HTML 5 history : HTML 5 history API 를 사용하는 것이 현대적인 방법입니다.
    이 모드에는 해시가 필요하지 않습니다.

이 기사에서는 HTML 5 history 모드 를 사용하고 history API 를 사용하는 방법을 살펴보겠습니다. 그러나 해시 모드를 사용하려면 약간의 변경이 필요합니다.

히스토리 모듈 구현

History API에는 window.location 할당 대신 사용할 수 있는 pushState 메서드가 있습니다.

pushState 방법은 window.location 할당과 달리 강제 리로드를 수행하지 않으므로 사용하기 적합합니다.

그에 따라 App.vue 에서 goTo 메서드를 업데이트할 수 있습니다.

// App.vue
goTo(route) {
  history.pushState(null, null, route)
}

호출에서 처음 두 개의 매개변수(statetitle)를 생략할 수 있습니다. 세 번째 매개변수로 수신된 route에 관심을 주세요.

그러나 여전히 문제가 있습니다. pushState를 사용하여 경로를 설정하더라도 Router.vue 에서 구성 요소를 업데이트하기 위해 경로 변수 current가 변경되었음을 알아야 합니다.

이미 History API에 익숙 하다면 onpopstate 이벤트를 사용할 수 있다고 생각할 수도 있지만 자세히 읽어보면 pushState가 호출 될 때 이벤트가 트리거되지 않는다는 것을 알 수 있습니다. 우리는 여전히 사용자가 뒤로 및 앞으로 브라우저 버튼을 눌렀을 때 그 변화에 반응 할 필요가 있지만 충분하지 않습니다.

이를 해결하기 위해 변경 사항을 수신하고 대신 호출 할 수 있는 기록 래퍼를 만들 수 있습니다. history.js 파일을 만들고 push 메서드를 래핑하여 시작하겠습니다.

// history.js
export const push = route => {
    window.history.pushState(null, null, route);
}

히스토리를 청취 가능하게 만들려면 외부 모듈이 변경 사항을 알리는 데 사용할 listen 콜백 함수를 listeners 변수에 저장하는 메서드를 구현해야 합니다 .

// history.js
const listeners = [];

export const push = route => {
  window.history.pushState(null, null, route);
};

export const listen = fn => {
  listeners.push(fn);
};

마지막으로 push 메서드는 실제로 리스너를 반복하여 알림을 보내고 경로를 전달하는 콜백 함수를 호출해야 합니다. 이전 경로와 두 번째 인수를 전달할 수 있습니다.

push(route) {
  const previousRoute = window.location.pathname;
  window.history.pushState(null, null, route);
  listeners.forEach(listener => listener(route, previousRoute));
}

외부 모듈에 알리기 위해 리스너를 사용하는 이러한 방식이 친숙해 보인다면, 다른 구성 요소가 변경 사항을 수신할 수 있는 구독 모델을 제공하는 구조를 제공하는 패턴인 Observer Patternhistory.js가 구현 하기 때문 입니다.

최종 코드는 다음과 같습니다.

// history.js
const listeners = [];

export const push = route => {
  const previousRoute = window.location.pathname;
  window.history.pushState(null, null, route);
  listeners.forEach(listener => listener(route, previousRoute));
};

export const listen = fn => {
  listeners.push(fn);
};

history.js 모듈도 NPM에 게시 된 외부 패키지로 사용할 수 있습니다. 사실 React Router 팀이 React Router를 위해 생성한 기존 history npm 패키지가 있지만, 독립적인 모듈이고 API가 거의 동일하기 때문에 이 경우 완벽하게 사용할 수 있습니다.

히스토리 모듈 사용

이제 history.js 가 구현되었습니다. pushState 호출을 대신하여 App.vue 에서 사용하겠습니다.

// App.vue
import Router from "./Router";
import { push } from "./history";

export default {
  components: {
    Router
  },
  methods: {
    goTo(route) {
     push(route);
    }
  }
};

여전히 AppRouter.vue 구성 요소가 URL 변경 사항을 인식하도록 해야 하며 이제 history 모듈의 listen 메서드를 사용할 수 있습니다. 리스너를 한 번만 설정하면 되므로 Vue.js 구성 요소의 created 후크가 완벽한 위치입니다.

// AppRouter.vue
import { listen } from "./history";

// ...

export default {
  created() {
   listen((route, previousRoute) => {
      this.current = route
    });
  },
  // ...
}

listen 명령문에 전달된 함수는 history의 리스너에 추가된 다음 나중에 호출될 때 push가 호출됩니다.

이제 HomeArticles 버튼을 클릭 하면 작동합니다. 그러나 당신은 브라우저의 뒤로 및 앞으로의 버튼을 클릭하면 여전히 작동하지 않습니다. 이전에 언급했듯이 이를 위해 popstate 이벤트를 사용해야 하므로 라우터의 created 후크에 추가하고 다음과 같이 마무리합니다.

created() {
 listen((route, previousRoute) => {
    this.current = route
  });

  window.addEventListener(
    "popstate",
    event => (this.current = window.location.pathname)
  );
}

마지막으로 다시 시도하면 모든 경우에 완벽하게 작동하는 간단한 라우터입니다. 여기에서 더 많은 기능을 추가할 수 있습니다. 후크와 가드를 추가하는 것은 어떻습니까?

여기 에서 이 기사 의 코드와 데모 를 찾아 직접 사용해 보세요!

댓글남기기