Intersection Observer Issues

I'm working on a game and I want some elements to animate in when they become visible, so I'm using intersection observers. I came up with this solution, and it works perfectly on firefox, but it sometimes bugs out on chrome. Sometimes the elements don't appear, and the screens stays like on pic related. Here's the relevant code
//get_observer.ts
export default function get_observer(
element: HTMLElement,
set_isVisible: (isVisible: boolean) => void,
threshold: number,
toggle: boolean
) {
const observer = new IntersectionObserver(
(entries) => {
const target = entries[0];

if (target.isIntersecting) set_isVisible(true);
else if (toggle) set_isVisible(false);
},
{ threshold }
);

observer.observe(element);

return observer;
}
//get_observer.ts
export default function get_observer(
element: HTMLElement,
set_isVisible: (isVisible: boolean) => void,
threshold: number,
toggle: boolean
) {
const observer = new IntersectionObserver(
(entries) => {
const target = entries[0];

if (target.isIntersecting) set_isVisible(true);
else if (toggle) set_isVisible(false);
},
{ threshold }
);

observer.observe(element);

return observer;
}
//Component.tsx
import { createSignal, onCleanup } from "solid-js";
import get_observer from "../get_observer.ts";

export default function Cmp() {
const [isVisible, setIsVisible] = createSignal(false);
const [observer, setObserver] = createSignal();

function set_observer(element: HTMLElement) {
const observer = get_observer(element, setIsVisible, .5, false);

setObserver(observer);
}

onCleanup(() => observer()?.disconnect());

return (
<div ref={set_observer}>
<div
class="invisible"
classList={{ "anime-enter": isVisible() }}
>
</div>
</div>
);
}
//Component.tsx
import { createSignal, onCleanup } from "solid-js";
import get_observer from "../get_observer.ts";

export default function Cmp() {
const [isVisible, setIsVisible] = createSignal(false);
const [observer, setObserver] = createSignal();

function set_observer(element: HTMLElement) {
const observer = get_observer(element, setIsVisible, .5, false);

setObserver(observer);
}

onCleanup(() => observer()?.disconnect());

return (
<div ref={set_observer}>
<div
class="invisible"
classList={{ "anime-enter": isVisible() }}
>
</div>
</div>
);
}
/* styles.css */

.invisible {
transform: translate(-100px);
opacity: 0;
}

.anime-enter {
transform: translate(-100px);
opacity: 0;
animation: enter-anime .33s forwards;

@keyframes enter-anime {
from {
transform: translate(-100px);
opacity: 0;
}

to {
transform: translate(0);
opacity: 1;
}
}
}
/* styles.css */

.invisible {
transform: translate(-100px);
opacity: 0;
}

.anime-enter {
transform: translate(-100px);
opacity: 0;
animation: enter-anime .33s forwards;

@keyframes enter-anime {
from {
transform: translate(-100px);
opacity: 0;
}

to {
transform: translate(0);
opacity: 1;
}
}
}
I know there's a library, but since this is a learning project I'd like to do it from scratch to understand things better. repo: https://github.com/kxrn0/fem_hangman
GitHub
GitHub - kxrn0/fem_hangman
Contribute to kxrn0/fem_hangman development by creating an account on GitHub.
No description
4 Replies
bigmistqke
bigmistqke10mo ago
from just looking at ur code here: are you sure you want to disconnect() on each unmount/cleanup of that Cmp-component?
bigmistqke
bigmistqke10mo ago
if you could make a minimal repro on http://playground.solidjs.com i can have a deeper look, but i m too lazy to git clone
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
microsoft
microsoftOP10mo ago
removing onCleanup(() => observer()?.disconnect()); does seem to get rid of the bug
bigmistqke
bigmistqke10mo ago
I just looked again at ur code. It worked a bit differently then I initially thought: I thought you had 1 global intersection-observer and then used this set_observer to observer.observe(...) the element, but instead you are creating a new IntersectionObserver for each element. In that case you do want to remove the observer onCleanup I suppose and your code should work. Maybe it's due to the fact that with <div ref={set_observer}/> set_observer is also called during unmount (with value undefined)... idk 🤷‍♂️ i would have to run the code to be able to see that. I would personally go for 1 global IntersectionObserver and use observer.unobserve to unobserve the element during cleanup/unmount.
Want results from more Discord servers?
Add your server