-
Notifications
You must be signed in to change notification settings - Fork 30
Description
Hello,
So my issue is a weird one and I have no clue what is happening.
I have a Detail.ts
page which receive props from an API. The data are fetched in the App.ts
file. You can see both files below.
App.ts
{
path: '/detail/:urn',
component: detailPage,
announce: 'Page Détail',
options: { keepAlive: true },
hooks: {
async before(to, from) {
// @ts-expect-error Blits typing issue
this.$appState.previousPageHash = from !== undefined ? from.hash : ''
// this.$appState.isPageLoading = true
if (!to.params?.urn) {
return '/error'
}
try {
const { data, error, success } = await apiManager.fetchDetail(to.params?.urn as string)
if (!success || error || !data) {
console.error('Failed to fetch Detail data:', error)
return '/error'
}
const { urn, gradientColor, hero, tabColor, tabs } = data
to.data = {
urn,
gradientColor,
hero,
tabColor,
tabs,
backButtonText: getBackButtonText(from),
}
return to
} catch (e) {
return '/error'
}
},
},
},
Detail.ts
:
import Blits from '@lightningjs/blits'
import Hero from '@components/organisms/Hero'
import Tabs from '@/components/molecules/Tabs'
import BackButton from '@/components/atoms/BackButton'
import DetailHero from '@/components/organisms/hero/details/DetailHero'
import { DISMISS_SPLASHSCREEN } from '@/App'
import { processImageUrl } from '@/utils/api/imageProxy'
import { DetailHeroItem, DetailTabs } from '../utils/types'
import { PageDetail } from '@/utils/api/ApiManager'
const DEFAULT_DETAIL_HERO_DATA: Omit<DetailHeroItem, 'downloadButton' | 'shareButton'> = {
urn: '',
title: '',
logo: null,
image: { url: '', alt: '' },
playButton: { icon: 'Play', label: 'Lire', urn: '', accessibilityLabel: '' },
myListButton: {
value: false,
inactive: { icon: 'MyList', label: 'Ma liste', accessibilityLabel: '' },
active: { icon: 'Checkmark', label: 'Dans ma liste', accessibilityLabel: '' },
},
progress: null,
tagline: '',
oneLiner: null,
labels: [],
}
const DEFAULT_DETAIL_DATA: Omit<PageDetail, 'hero'> & { hero: Omit<DetailHeroItem, 'downloadButton' | 'shareButton'> } = {
urn: '',
gradientColor: '',
hero: DEFAULT_DETAIL_HERO_DATA,
tabColor: '',
tabs: [],
}
export default Blits.Component('Detail', {
components: {
Hero,
Tabs,
BackButton,
DetailHero,
},
template: `
<Element color="black">
<Element :y.transition="$heroDetailsOffset" z="1">
<BackButton
z="1"
ref="details-item-0"
text="$backButtonText"
x="$$theme.get('columns.margin')"
y="$$theme.get('rows.margin')"
/>
<!--<Hero
:src="$proxyImage($hero?.image?.url)"
:blurredSrc="$proxyImage($hero?.image?.url, true)"
:gradientColor="$gradientColor"
childMount="{y: -0.9}"
>
<DetailHero slot="hero-content" ref="details-item-1" :data="$hero" />
</Hero>-->
<Text :content="$hero?.title" />
</Element>
<Element
z="1"
w="$$theme.get('viewport.width')"
h="$$theme.get('viewport.height')"
:shader="$shader('gradient', {
colors: [$gradientColor || '#000000', '#000000'],
stops: [0, 40],
alphas: [1.0, 1.0],
})"
:y.transition="$gradientOffset"
/>
<Tabs z="2" ref="details-item-2" :tabs="$tabs" x="$$theme.get('columns.margin')" :y.transition="$tabsOffset" />
</Element>
`,
props: [
{ key: 'urn', default: DEFAULT_DETAIL_DATA.urn },
{ key: 'gradientColor', default: DEFAULT_DETAIL_DATA.gradientColor },
{ key: 'tabColor', default: DEFAULT_DETAIL_DATA.tabColor },
{ key: 'hero', default: DEFAULT_DETAIL_DATA.hero },
{ key: 'tabs', default: DEFAULT_DETAIL_DATA.tabs },
{ key: 'detailData', default: DEFAULT_DETAIL_DATA },
{ key: 'backButtonText', default: 'Homepage' },
],
state() {
return {
focused: 1,
}
},
hooks: {
ready() {
this.$emit(DISMISS_SPLASHSCREEN)
},
focus() {
if (this.$appState.isPageLoading) this.$appState.isPageLoading = false
this.$trigger('focused')
},
},
computed: {
testTitle() {
return 'test title ' + this.urn
},
heroDetailsOffset() {
if (this.focused <= 1) return 0
return -(this.focused - 1) * 1100
},
tabsOffset() {
if (this.focused <= 1) return 1042
return -(this.focused - 1) * 1000 + 1030
},
gradientOffset() {
if (this.focused <= 1) return 1080
return -(this.focused - 1) * 1100 + 1080
},
},
methods: {
proxyImage(url: string | undefined, blurred: boolean = false) {
if (!url) return ''
return processImageUrl(url, null, blurred)
},
},
watch: {
focused(value: number) {
const item = this.$select('details-item-' + value)
if (item && item.$focus) {
item.$focus()
}
},
'$router.state.navigating'() {
if (!this.$router.state.navigating && this.$router.currentRoute.path === 'details/:id')
this.$appState.isPageLoading = false
},
},
input: {
up() {
this.focused = Math.max(0, this.focused - 1)
},
down() {
this.focused = Math.min(2, this.focused + 1)
},
},
})
The issue I have is that when for example I am in the home page, go the a detail page, go back and go to another detail page, It randomly crash with the following error:

At first I thought something was undefined, but that's not the case, every data seems to be there when I log the returned to from the before
hook. Then I found out the error was emitted by both the Hero
and HeroDetail
components, which both receive the hero
props. After commenting those components, everything works as intended. Then I tried to place a random text which receive $hero.title
and the problem was back again.
The issue is that as I said, hero
and hero.title
are defined so there is not reason for it to crash in my opinion so I suspect maybe there's something wrong with how data is passed to the page?
Here you can see that the before hook logs the data but it stills crash in the end

Below you can find two videos. One where $hero.title
and the app crashes, and another one where the props urn
from the API is used and everything works fine.
crash with $hero.title
:
app-crash.mp4
works fine with $urn
:
app-works.mp4
Really not sure what is happening here, not even sure if it's something internal or it has something to do with my data, but if you have any insight I'd happily hear them.
EDIT: I updated to 1.38.3, issue is still here the only difference is that the app crashes before navigation so I don't see a black screen anymore