Subscribe on changes!

KeepAlive provide function to delete cache

avatar
May 31st 2022

What problem does this feature solve?

We can open multiple tabs. The components corresponding to the tabs use the keepalive cache. We need to destroy the keepalive cache when closing the tabs to release the cache. We also know KeepAlive max property but that can't delete specified cache. hope expose keys and cache property in production

What does the proposed API look like?

hope expose keys and cache property in production or provide function to delete cache by key

avatar
Jun 6th 2022

Has this PR passed? @lidlanca

avatar
Jun 6th 2022

its been open for more than a year, I don't know what blocks it.

avatar
Aug 5th 2022

maybe you can do it use KeepAlive.

If use router controll it, record route:

// record tabs
const pages = reactive([]);

// when route changed, record it
router.afterEach((to) => {
  const key = getKeyFromRoute(to);
  if (pages.find((tab) => tab.key === key)) {
    return;
  }
  pages.push({
    key,
    component: null,
  });
});

// calc key of the route
function getKeyFromRoute(route) {
  const keepAlive = route.meta.keepAlive ?? "path";

  return keepAlive === "path"
    ? route.path
    : keepAlive === "fullPath"
    ? route.fullPath
    : route.name;
}

then, render router view:


// render the router view
function setup() {
  // keepalive components name
  const includes = ref([]);

  // when tabs changed, calc the includes
  watch(
    () => pages,
    () => {
      // delay update, because of current component's onUnmounted callback
      requestIdleCallback(() => {
        includes.value = theme.pages
          .filter((tab) => tab.keepAlive)
          .map((tab) => `Route@${tab.key}`);
      });
    }
  );

  return () => (
    <RouterView>
      {{
        default: ({ Component, route }) => {
          if (!Component) return null;
          const key = getKeyFromRoute(route);
          // notice, use reactive var 'pages' in slots function maybe cause this slot duplicate render. 
          // should use other var to avoid it
          const tab = pages.find((tab) => key === tab.key);
          if (!tab) return null;

          // wrapper component name use key of route
          if (!tab.component) {
            tab.component = markRaw(
              defineComponent({
                name: `Route@${key}`,
                render: () => Component,
              })
            );
          }

          const RouterViewRender = tab.component;

          return (
            <KeepAlive include={includes.value}>
              <RouterViewRender />
            </KeepAlive>
          );
        },
      }}
    </RouterView>
  );
}

when close tab, delete tab from pages:

function close(tabIndex) {
  pages.slice(tabIndex, 1)
}
avatar
Aug 8th 2022

maybe you can do it use KeepAlive.

If use router controll it, record route:

// record tabs
const pages = reactive([]);

// when route changed, record it
router.afterEach((to) => {
  const key = getKeyFromRoute(to);
  if (pages.find((tab) => tab.key === key)) {
    return;
  }
  pages.push({
    key,
    component: null,
  });
});

// calc key of the route
function getKeyFromRoute(route) {
  const keepAlive = route.meta.keepAlive ?? "path";

  return keepAlive === "path"
    ? route.path
    : keepAlive === "fullPath"
    ? route.fullPath
    : route.name;
}

then, render router view:

// render the router view
function setup() {
  // keepalive components name
  const includes = ref([]);

  // when tabs changed, calc the includes
  watch(
    () => pages,
    () => {
      // delay update, because of current component's onUnmounted callback
      requestIdleCallback(() => {
        includes.value = theme.pages
          .filter((tab) => tab.keepAlive)
          .map((tab) => `Route@${tab.key}`);
      });
    }
  );

  return () => (
    <RouterView>
      {{
        default: ({ Component, route }) => {
          if (!Component) return null;
          const key = getKeyFromRoute(route);
          // notice, use reactive var 'pages' in slots function maybe cause this slot duplicate render. 
          // should use other var to avoid it
          const tab = pages.find((tab) => key === tab.key);
          if (!tab) return null;

          // wrapper component name use key of route
          if (!tab.component) {
            tab.component = markRaw(
              defineComponent({
                name: `Route@${key}`,
                render: () => Component,
              })
            );
          }

          const RouterViewRender = tab.component;

          return (
            <KeepAlive include={includes.value}>
              <RouterViewRender />
            </KeepAlive>
          );
        },
      }}
    </RouterView>
  );
}

when close tab, delete tab from pages:

function close(tabIndex) {
  pages.slice(tabIndex, 1)
}

This seems to work by redefine component name , let me try.