Экземпляр 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
}

Другие вопросы по тегам