feat: preserving state between route changes (#132)
parent
d967520005
commit
6414f2a4e2
|
@ -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)
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import type { Paginator } from 'masto'
|
import type { Paginator } from 'masto'
|
||||||
|
import { useDeactivated } from './lifecycle'
|
||||||
import type { PaginatorState } from '~/types'
|
import type { PaginatorState } from '~/types'
|
||||||
|
|
||||||
export function usePaginator<T>(paginator: Paginator<any, T[]>) {
|
export function usePaginator<T>(paginator: Paginator<any, T[]>) {
|
||||||
|
@ -10,6 +11,7 @@ export function usePaginator<T>(paginator: Paginator<any, T[]>) {
|
||||||
const bound = reactive(useElementBounding(endAnchor))
|
const bound = reactive(useElementBounding(endAnchor))
|
||||||
const isInScreen = $computed(() => bound.top < window.innerHeight * 2)
|
const isInScreen = $computed(() => bound.top < window.innerHeight * 2)
|
||||||
const error = ref<unknown | undefined>()
|
const error = ref<unknown | undefined>()
|
||||||
|
const deactivated = useDeactivated()
|
||||||
|
|
||||||
async function loadNext() {
|
async function loadNext() {
|
||||||
if (state.value !== 'idle')
|
if (state.value !== 'idle')
|
||||||
|
@ -44,7 +46,12 @@ export function usePaginator<T>(paginator: Paginator<any, T[]>) {
|
||||||
watch(
|
watch(
|
||||||
() => isInScreen,
|
() => 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()
|
loadNext()
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
|
|
|
@ -53,4 +53,7 @@ export default defineNuxtConfig({
|
||||||
translateApi: '',
|
translateApi: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
app: {
|
||||||
|
keepalive: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
import type { ComponentPublicInstance } from 'vue'
|
import type { ComponentPublicInstance } from 'vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const id = $computed(() => route.params.status as string)
|
const id = $(computedEager(() => route.params.status as string))
|
||||||
const main = ref<ComponentPublicInstance | null>(null)
|
const main = ref<ComponentPublicInstance | null>(null)
|
||||||
let bottomSpace = $ref(0)
|
let bottomSpace = $ref(0)
|
||||||
|
|
||||||
const status = window.history.state?.status ?? await fetchStatus(id)
|
const { data: status, refresh: refreshStatus } = useAsyncData(async () => window.history.state?.status ?? await fetchStatus(id))
|
||||||
const { data: context, pending } = useAsyncData(`context:${id}`, () => useMasto().statuses.fetchContext(id))
|
const { data: context, pending, refresh: refreshContext } = useAsyncData(`context:${id}`, () => useMasto().statuses.fetchContext(id))
|
||||||
|
|
||||||
function scrollTo() {
|
function scrollTo() {
|
||||||
const statusElement = unrefElement(main)
|
const statusElement = unrefElement(main)
|
||||||
|
@ -27,6 +27,13 @@ if (pending) {
|
||||||
scrollTo()
|
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()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const params = useRoute().params
|
const params = useRoute().params
|
||||||
const accountName = $computed(() => toShortHandle(params.account as string))
|
const accountName = $(computedEager(() => toShortHandle(params.account as string)))
|
||||||
|
|
||||||
const account = await fetchAccountByName(accountName).catch(() => null)
|
const { data: account, refresh } = $(await useAsyncData(() => fetchAccountByName(accountName).catch(() => null)))
|
||||||
|
|
||||||
if (account) {
|
if (account) {
|
||||||
useHead({
|
useHead({
|
||||||
title: () => `${getDisplayName(account)} (@${account.acct})`,
|
title: () => `${getDisplayName(account)} (@${account.acct})`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
refresh()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const params = useRoute().params
|
const params = useRoute().params
|
||||||
const accountName = $computed(() => params.account as string)
|
const accountName = $(computedEager(() => params.account as string))
|
||||||
|
|
||||||
const account = await fetchAccountByName(accountName)
|
const account = await fetchAccountByName(accountName)
|
||||||
const paginator = account ? useMasto().accounts.getFollowersIterable(account.id, {}) : null
|
const paginator = account ? useMasto().accounts.getFollowersIterable(account.id, {}) : null
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const params = useRoute().params
|
const params = useRoute().params
|
||||||
const accountName = $computed(() => params.account as string)
|
const accountName = $(computedEager(() => params.account as string))
|
||||||
|
|
||||||
const account = await fetchAccountByName(accountName)
|
const account = await fetchAccountByName(accountName)
|
||||||
const paginator = account ? useMasto().accounts.getFollowingIterable(account.id, {}) : null
|
const paginator = account ? useMasto().accounts.getFollowingIterable(account.id, {}) : null
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const params = useRoute().params
|
const params = useRoute().params
|
||||||
const accountName = $computed(() => params.account as string)
|
const accountName = $(computedEager(() => params.account as string))
|
||||||
|
|
||||||
const account = await fetchAccountByName(accountName)
|
const account = await fetchAccountByName(accountName)
|
||||||
const tabNames = ['Posts', 'Posts & replies', 'Media'] as const
|
const tabNames = ['Posts', 'Posts & replies', 'Media'] as const
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const params = useRoute().params
|
const params = useRoute().params
|
||||||
const tag = $computed(() => params.tag as string)
|
const tag = $(computedEager(() => params.tag as string))
|
||||||
|
|
||||||
const paginator = useMasto().timelines.getHashtagIterable(tag)
|
const paginator = useMasto().timelines.getHashtagIterable(tag)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue