Экземпляр H5P дублируется в reactjs
Я разрабатываю автономный плагин h5p в реакции (nextjs), передавая путь в качестве реквизита модальному компоненту, который отображает активность h5p.
С помощью этого кода я получаю два изображения h5p на экране. Поэтому я использую removeAllChildren(), чтобы исключить их из рендеринга.
function removeAllChildNodes(parent) {
console.log(parent)
while (parent.firstChild) {
parent.removeChild(parent.firstChild)
}
}
Этот хак работает нормально, но когда я пытаюсь отправить оператор xAPI в свою базу данных, он срабатывает дважды.
const fireCompleteH5PTopic = async (H5P) => {
H5P.externalDispatcher.on("xAPI", (event) => {
// console.log('event fired')
if (event?.data?.statement?.result?.completion) {
setCounter(counter + 1)
completeH5PTopic(event, session.data.user.id, course.slug, topic)
return true
}
})
}
Любая помощь относительно того, почему он срабатывает дважды? Я думаю, что это может быть связано с рендерингом h5p дважды.
Заранее спасибо.
Я пытался использовать состояние для рендеринга только один раз, но это не работает.
1 ответ
В итоге я сделал это:
import { useEffect, useMemo, useState } from 'react'
import { Loading } from '../../../Animations/Loading'
import { completeH5PTopic } from '../../../../lib/sinapsis/gamification'
import { useSession } from 'next-auth/react' // ES6
import ToastGamification from '../../../Notificaciones/ToastGamification'
import { toast } from 'react-hot-toast'
import { useRef } from 'react'
const POINTS_PER_TOPIC_COMPLETED = 5
const H5PContainer = ({ location, course, topic }) => {
const H5PStandalone = useMemo(() => require('h5p-standalone').H5P, [])
const [isLoaderVisible, setIsLoaderVisible] = useState(true)
let firstTime = true
const h5pPath = `https://mycdn.com/h5p-v1/${location}`
const { data } = useSession()
const user = data?.user
// console.log(user, 'user')
const name = ''
const options = {
h5pJsonPath: h5pPath,
frameJs: '/h5p/dist/frame.bundle.js',
frameCss: '/h5p/dist/styles/h5p.css',
}
const h5pRef = useRef(null)
// console.log('H5PStandalone', H5PStandalone)
const loadH5PComponent = async () => {
if (h5pRef.current && window) {
await new H5PStandalone(h5pRef.current, options)
setIsLoaderVisible(false)
window.H5P.externalDispatcher.on('xAPI', (event) => {
//do something useful with the event
// console.log(event, 'event')
// console.log('results:', event.getScore(), '---->', name)
if (
event.getScore() > 1 ||
event.data.statement.verb.display['en-US'] === 'completed'
) {
fireCompleteH5PTopicFn(
window.H5P,
user?.id,
course?.slug,
topic?.slug,
)
}
})
}
}
useEffect(() => {
if (firstTime) {
const hasChildren = h5pRef.current.children
if (hasChildren.length !== 0) {
const parent = hasChildren[0].parentNode
parent.removeChild(hasChildren[0])
}
loadH5PComponent()
firstTime = false
// setIsLoaderVisible(false)
}
}, [name])
return (
<div className="w-full h-full ">
{isLoaderVisible && <Loading />}
<div id={`h5p-container-${location}`} ref={h5pRef} />
</div>
)
}
export default H5PContainer
async function fireCompleteH5PTopicFn(userId, courseSlug, topic) {
const res = await completeH5PTopic(userId, courseSlug, topic)
toast.dismiss()
if (res.status === 200) {
toast.custom((t) => (
<ToastGamification
isVisible={t.visible}
onDismiss={() => toast.dismiss(t.id)}
points={POINTS_PER_TOPIC_COMPLETED}
/>
))
}
return true
}