From 6414f2a4e2de10c8576cc2372247c03e5305472e Mon Sep 17 00:00:00 2001 From: Ayaka Rizumu <464388324@qq.com> Date: Mon, 28 Nov 2022 01:34:45 +0800 Subject: [PATCH] feat: preserving state between route changes (#132) --- composables/lifecycle.ts | 30 ++++++++++++++++++++++++++++ composables/paginator.ts | 9 ++++++++- nuxt.config.ts | 3 +++ pages/@[account]/[status].vue | 13 +++++++++--- pages/@[account]/index.vue | 10 ++++++++-- pages/@[account]/index/followers.vue | 2 +- pages/@[account]/index/following.vue | 2 +- pages/@[account]/index/index.vue | 2 +- pages/tags/[tag].vue | 2 +- 9 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 composables/lifecycle.ts diff --git a/composables/lifecycle.ts b/composables/lifecycle.ts new file mode 100644 index 00000000..b6d06e1b --- /dev/null +++ b/composables/lifecycle.ts @@ -0,0 +1,30 @@ +import type { ComponentInternalInstance } from 'vue' +import { onActivated, onDeactivated, ref } from 'vue' + +/** + * ### Whether the current component is running in the background + * + * for handling problems caused by the keepalive function + */ +export function useDeactivated() { + const deactivated = ref(false) + onActivated(() => deactivated.value = false) + onDeactivated(() => deactivated.value = true) + + return deactivated +} + +/** + * ### When the component is restored from the background + * + * for handling problems caused by the keepalive function + */ +export function onReactivated(hook: Function, target?: ComponentInternalInstance | null): void { + const initial = ref(true) + onActivated(() => { + if (initial.value) + return + hook() + }, target) + onDeactivated(() => initial.value = false) +} diff --git a/composables/paginator.ts b/composables/paginator.ts index a21f1c91..10dc1196 100644 --- a/composables/paginator.ts +++ b/composables/paginator.ts @@ -1,4 +1,5 @@ import type { Paginator } from 'masto' +import { useDeactivated } from './lifecycle' import type { PaginatorState } from '~/types' export function usePaginator(paginator: Paginator) { @@ -10,6 +11,7 @@ export function usePaginator(paginator: Paginator) { const bound = reactive(useElementBounding(endAnchor)) const isInScreen = $computed(() => bound.top < window.innerHeight * 2) const error = ref() + const deactivated = useDeactivated() async function loadNext() { if (state.value !== 'idle') @@ -44,7 +46,12 @@ export function usePaginator(paginator: Paginator) { watch( () => isInScreen, () => { - if (isInScreen && state.value === 'idle') + if ( + isInScreen + && state.value === 'idle' + // No new content is loaded when the keepAlive page enters the background + && deactivated.value === false + ) loadNext() }, { immediate: true }, diff --git a/nuxt.config.ts b/nuxt.config.ts index 27701dd2..ea3b0ace 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -53,4 +53,7 @@ export default defineNuxtConfig({ translateApi: '', }, }, + app: { + keepalive: true, + }, }) diff --git a/pages/@[account]/[status].vue b/pages/@[account]/[status].vue index cd223233..4e67bcc8 100644 --- a/pages/@[account]/[status].vue +++ b/pages/@[account]/[status].vue @@ -2,12 +2,12 @@ import type { ComponentPublicInstance } from 'vue' const route = useRoute() -const id = $computed(() => route.params.status as string) +const id = $(computedEager(() => route.params.status as string)) const main = ref(null) let bottomSpace = $ref(0) -const status = window.history.state?.status ?? await fetchStatus(id) -const { data: context, pending } = useAsyncData(`context:${id}`, () => useMasto().statuses.fetchContext(id)) +const { data: status, refresh: refreshStatus } = useAsyncData(async () => window.history.state?.status ?? await fetchStatus(id)) +const { data: context, pending, refresh: refreshContext } = useAsyncData(`context:${id}`, () => useMasto().statuses.fetchContext(id)) function scrollTo() { const statusElement = unrefElement(main) @@ -27,6 +27,13 @@ if (pending) { scrollTo() }) } + +onReactivated(() => { + // Silently update data when reentering the page + // The user will see the previous content first, and any changes will be updated to the UI when the request is completed + refreshStatus() + refreshContext() +})