blog

keep-aliveを使用して、最小限のコストでページ状態の保持を実現する

プロジェクト開発において、あるページから別のページにジャンプして戻るときに、ジャンプ前の状態を維持しなければならないという要件に遭遇しました。 例えば、ユーザがリストでフィルタリングを行い、フィルタリ...

Mar 30, 2020 · 5 min. read
シェア

どのような問題が解決されるのですか?

あるページから別のページにジャンプし、またジャンプして戻るとき、ジャンプ前の見た目を維持しなければならないです

たとえば、ユーザーがリストでフィルタリングを行い、フィルタリングページをクリックして詳細を表示し、フィルタリングの条件と結果が保持されていることを期待してリストページにジャンプバックした場合。

これにはいくつかの選択肢があります:

  1. データの埋め戻し。新しいページにジャンプするときに、古いページに保存する必要があるデータを引き継ぎ、ジャンプバックするときにページを埋めます。

  2. グローバル変数やvuexなどを使用して、古いページのデータを状態管理し、ページが戻ったときにそれを埋めます。

  3. 新しいページにジャンプする代わりに、元のページをポップアップレイヤーで上書きするか、元のコンポーネントを非表示にして新しいページのコンテンツを表示します。

上記の3つのオプションのうち、各ケースの最初のオプションは、独自の処理を行うために、データを渡すために、面倒でエラーが発生しやすい、2番目のオプションは、独自のデータを渡す必要はありませんが、状態の管理も大きな問題であり、ときに格納するために、クリアするために、バックフィルするときに、すべてを考慮する必要があり、さらに最初のオプションのように、緊密に結合のビジネス。

だから、3番目のオプションは、最適なソリューションであるように思われる、ちょうど自然の状態が失われることはありません非表示にするため、元のコンポーネントを非表示にし、ビジネスについてはほとんど気にせず、との間のデータのストレージを気にする必要はありません。

しかし!ブラウザのリフレッシュとフォールバックです。

確かに、3番目のオプションはシンプルで便利ですが、無視できない一般的なユーザーの習慣があります。

3番目のオプションを使用すると、新しいページの本質は開かれませんが、唯一の古いコンテンツでは、新しいコンテンツを非表示にし、表示します。しかし、ユーザーは、それが本質的に新しいページであるかどうかを気にしない、それは別のページのように見え、その後、更新をクリックしたときに、それは新しいコンテンツでリフレッシュする必要があり、誰が知っているが、前の場所に戻って、1つだけのレイヤーを返すことを期待して戻ってクリックしますが、上の上のレイヤーに返されます。

例えば、このバグ...

1.ページAに移動し、ボタンをクリックし、ページBに移動し、ブラウザの更新ボタンをクリックする。
 実際の結果
 ページBを終了し、ページAに戻った
 期待される結果
 ステイアライブページ B
2.ページAに移動し、ボタンをクリックし、ページBに移動し、ブラウザの戻るボタンをクリックする。
 実際の結果
 ページBを終了し、無関係なページCにジャンプした。
 期待される結果
 ページAに戻る

そのため、keep-alive .

どのように機能するのですか?

keep-aliveはコンポーネントをキャッシュする問題を解決し、ルートレベルのコンポーネントもキャッシュできるという驚きの発見をしました。しかし、これは多かれ少なかれ落とし穴でもあります。

  • ルートレベルのコンポーネントでkeep-aliveを使うときは、その上に別のルーティングの層がなければなりません。

  • キャッシュを簡単にクリアできません。

少し調べてみたところ、キャッシュを直接クリアするのは簡単ではありませんが、keep-aliveのincludeでキャッシュされるコンポーネントを制限し、キャッシュが必要なコンポーネントの名前をincludeに入れ、キャッシュをクリアする必要があるときに配列からその名前を削除すればよいことがわかりました。

ルートを設定するときにメタに判定関数を置き、ルートガードはその関数を呼び出して、キャッシュをクリアするか、キャッシュに追加するかを決定します。

実装

ルーティングラッパー関数

// cacheRoutes.js
const routerComponent = {
 template: `
 <template>
 <keep-alive :include="cacheArr">
 <router-view />
 </keep-alive>
 </template>
 `,
 data() {
 return {
 cacheArr: [],
 lastCacheRoute: {
 to: '',
 from: '',
 }
 }
 },
 methods: {
 cleanCache(nto, nfrom) {
 const {to, from} = this.lastCacheRoute;
 if (to !== nfrom || from !== nto) {
 this.cacheArr = [];
 this.lastCacheRoute = {
 to: '',
 from: '',
 };
 }
 },
 changeCache(to, from) {
 if (from.meta && from.meta.cache) {
 const cacheName = from.meta.cache(to, from);
 this.cacheArr = cacheName ? [cacheName]: [];
 this.lastCacheRoute = {
 to: to.name,
 from: from.name,
 };
 }
 }
 },
 created() {
 this.$router.beforeEach((to, from, next) => {
 this.cleanCache(to.name, from.name);
 this.changeCache(to, from);
 next();
 });
 },
};
export cacheRoutes(routes) {
 return [
 {
 path: '',
 component: routerComponent,
 children: routes,
 meta: {},
 redirect: routes[0] && routes[0].path || undefined
 }
 ];
}

注: これは単一レベルのキャッシュにのみ適用されます。例えば、A->BでAがキャッシュされますが、次のルートがAを返さない場合、Aのキャッシュは削除されます。

参照メソッド


import { cacheRoutes } from 'xxx/cacheRoutes.js';
...
let routes = [...] // オリジナルルート
routes = cacheRoutes(routes);
...

キャッシュのタイミング


// オリジナルルート
routes = [
...
 {
 path: '/test',
 component: () => import('@/views/pages/test/index.vue'),
 name: 'test',
 meta: {},
 },
...
];
// キャッシュタイミングを持つルート
routes = [
...
 {
 path: '/test',
 component: () => import('@/views/pages/test/index.vue'),
 name: 'test',
 meta: {
 cache: (to, from) => { // ルートへのルート、現在のルートのルート
 const {name, query} = to;
 if (name === 'test' && query.type === 'view') { // キャッシュが必要な場合、キャッシュされるコンポーネントの名前を返す。匿名コンポーネントはサポートされていない。
 return 'test';
 }
 return ''; // それ以外の場合は空文字列を返す
 }
 },
 },
...
];

また、keep-aliveキャッシュコンポーネントが有効化されたときに呼び出されるフック関数 activatedはキャッシュされたページに戻るときにデータを部分的にリフレッシュするために使うことができます

このフックはサーバサイドレンダリング中には呼び出されません

------------------------ e -------------- n ------------------- d ------------------------

[1]

[2]

Read next

REPプロジェクトとの付き合い方

WBTCとTBTCの競合として、RENは仕掛ける価値があるため、REPは当面考慮せず、MLN、GNO、REPも同様。 ZRXについては、0x Realyerを使用した総取引量は1日平均300万ドルから400万ドルに達する可能性があります。同時に、ZRX...

Mar 30, 2020 · 1 min read