I have a React functional component that renders a Lesson Video Player in a very similar way to the Instagram Stories. Some of those videos ("clips") in a lesson have "interactions" that pop up a card where the user answers a multiple-choice quiz. The code is simplified below.
On random lessons some interactions are not showing. In the log interactions 1 they show up as usual (a bunch of undefined values are logged and then after a few rerenders the array is logged) but when the onClipEnding function is called interactions 2 is undefined again.
Any clues on what might be happening? My best guess is a stale closure but I can't find a way to solve it.
export function getInteractions(lesson_id: string, profile_id?: string) {
const { data, error } = useSWR<ManyResponse<Interaction>>(
`${apiRoutes.interactions}/${lesson_id}?per_page=50${
profile_id ? `&profile_id=${profile_id}` : ''
}`,
request,
)
return {
interactions: data && data.data,
isLoading: !data && !error,
error,
}
}
export default function LessonPlayer({ videoIds }) {
const setVideos = useStoreActions((actions: Actions<Store>) => actions.setVideos)
const { interactions } = getInteractions(lessonId, currentProfileId)
console.log('interactions 1', interactions)
useEffect(() => {
if (!videoIds && videos) {
setVideos(videos)
}
}, [videoIds, setVideos])
return (
<>
<div>
{(videoIds || []).map((videoId) => (
<Video key={videoId} videoId={videoId} onEnd={onClipEnding} />
))}
</div>
{interactions && (
<div className="absolute bottom-0 w-full">
<InteractionCard interaction={interaction} handleInteraction={handleInteraction} />
</div>
)}
</>
)
function onClipEnding(videoId: string) {
const clipInteraction = interactions && interactions.find((item) => item.clip_id == videoId)
console.log('interactions 2', interactions)
if (clipInteraction) {
setInteraction(clipInteraction)
} else {
nextClip({ profile_id: currentProfileId, status: 'completed' })
}
}
It's the stale closure of onClipEnding
, that's created at initial render, which captures the interactions
variable of value undefined
, and then passed as a callback down to <Video />
via its onEnd
prop. Down there it's kept as the stale version at initial render and never updated until called.
Since you're aware of stale closure problem, I believe above info should be adequate for you to debug. I'll leave the rest to you.
Bonus: I share with you my secret weapon, a panacea for stale closure problems. Entering the useFn
custom hook:
function useFn(fn) {
const ref = useRef(fn);
ref.current = fn;
function wrapper() {
return ref.current.apply(this, arguments)
}
return useRef(wrapper).current
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.