useSWR 钩子表现不稳定或可能过时关闭
useSWR hook behaving erratically or possible stale closure
我有一个 React 功能组件,它以与 Instagram 故事非常相似的方式呈现课程视频播放器。课程中的某些视频(“剪辑”)具有 “互动”,会弹出一张卡片,用户可以在其中回答多项选择题。代码简化如下。
在随机课程中,一些 互动 没有显示。在日志 interactions 1 中,它们照常显示(记录了一堆未定义的值,然后在几次重新渲染后记录了数组)但是当 onClipEnding 函数被调用 interactions 2 再次未定义。
关于可能发生的事情的任何线索?我最好的猜测是陈旧的关闭,但我找不到解决它的方法。
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' })
}
}
这是 onClipEnding
的陈旧闭包,它是在初始渲染时创建的,它捕获值 undefined
的 interactions
变量,然后作为回调传递给 <Video />
通过其 onEnd
道具。在那里,它在初始渲染时保留为陈旧版本,直到被调用才更新。
既然你知道陈旧的闭包问题,我相信以上信息应该足以让你进行调试。剩下的就交给你了
奖励:我与您分享我的秘密武器,这是解决陈旧关闭问题的灵丹妙药。输入 useFn
自定义挂钩:
function useFn(fn) {
const ref = useRef(fn);
ref.current = fn;
function wrapper() {
return ref.current.apply(this, arguments)
}
return useRef(wrapper).current
}
我有一个 React 功能组件,它以与 Instagram 故事非常相似的方式呈现课程视频播放器。课程中的某些视频(“剪辑”)具有 “互动”,会弹出一张卡片,用户可以在其中回答多项选择题。代码简化如下。
在随机课程中,一些 互动 没有显示。在日志 interactions 1 中,它们照常显示(记录了一堆未定义的值,然后在几次重新渲染后记录了数组)但是当 onClipEnding 函数被调用 interactions 2 再次未定义。
关于可能发生的事情的任何线索?我最好的猜测是陈旧的关闭,但我找不到解决它的方法。
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' })
}
}
这是 onClipEnding
的陈旧闭包,它是在初始渲染时创建的,它捕获值 undefined
的 interactions
变量,然后作为回调传递给 <Video />
通过其 onEnd
道具。在那里,它在初始渲染时保留为陈旧版本,直到被调用才更新。
既然你知道陈旧的闭包问题,我相信以上信息应该足以让你进行调试。剩下的就交给你了
奖励:我与您分享我的秘密武器,这是解决陈旧关闭问题的灵丹妙药。输入 useFn
自定义挂钩:
function useFn(fn) {
const ref = useRef(fn);
ref.current = fn;
function wrapper() {
return ref.current.apply(this, arguments)
}
return useRef(wrapper).current
}