join us on Discord for support, updates, and all things Snap AR! See you there!
SnapAR CameraKit lens not loaded error in React
import React, { useEffect, useRef, useState } from "react" import { bootstrapCameraKit } from "@snap/camera-kit" const CameraKitComponent = () => { const canvasRef = useRef(null) // Reference to the canvas element const [lensId, setLensId] = useState("43293650876") // State to manage the current lens ID const [session, setSession] = useState(null) // State to manage the camera session const [cameraKit, setCameraKit] = useState(null) const [lensConfig, setLensConfig] = useState({ lensId: "43293650876", lensGroupId: "913dffcc-07d8-4f94-901f-297260c6c4a6", }) useEffect(() => { const initializeCameraKit = async () => { const apiToken = "API TOKEN" // Place your actual API token here const cameraKit = await bootstrapCameraKit({ apiToken }) setCameraKit(cameraKit) const liveRenderTarget = canvasRef.current if (!liveRenderTarget) { return } const newSession = await cameraKit.createSession({ liveRenderTarget }) const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, }) await newSession.setSource(mediaStream) await newSession.play() setSession(newSession) // Save the session to state } initializeCameraKit() return () => { session && session.stop && session.stop() } }, []) const applyLens = async (lensId, lensGroupId) => { if (!cameraKit || !session || !lensId || !lensGroupId) { return } try { const lens = await cameraKit.lensRepository.loadLens(lensId, lensGroupId) console.log("lens", lens) await session.applyLens(lens) } catch (error) { console.error("Error loading or applying lens:", error) } } useEffect(() => { if (lensConfig.lensId && lensConfig.lensGroupId) { applyLens(lensConfig.lensId, lensConfig.lensGroupId) // Update to pass lens group ID as well } }, [lensConfig, session, cameraKit]) return ( <div> <canvas ref={canvasRef}></canvas> <div> <button onClick={() => setLensConfig({ lensId: "43293650876", lensGroupId: "913dffcc-07d8-4f94-901f-297260c6c4a6", }) } > Load Lens 1 </button> <button onClick={() => setLensConfig({ lensId: "50502080875", lensGroupId: "913dffcc-07d8-4f94-901f-297260c6c4a6", }) } > Load Lens 2 </button> <button onClick={() => setLensConfig({ lensId: "50507980875", lensGroupId: "913dffcc-07d8-4f94-901f-297260c6c4a6", }) } > Load Lens 3 </button> </div> </div> ) } export default CameraKitComponent
The above is the code of my component.
What I am trying to do it loading different lenses in runtime based on the button clicked. It gives me the following error most of the time. It works once in a while.
Error loading or applying lens: Error: Cannot apply lens 43293650876. It has not been loaded by the Lens repository. Use CameraKit.lensRepository.loadLens (or loadLensGroups) to load lens metadata before calling CameraKitSession.applyLens.
I did try different methods including making a generic CameraKit componenet which is loaded based on given props (id and lens group id) Is there a way to make this work
Answers
-
Try to move "setSession(newSession)" line somewhere before "await newSession.play()". For example you can store the session right after "createSession()" call. Another approach if you want to keep the order of calls is to never await "newSession.play()".
A promise that is returned by a first call to "session.play()" is resolved when the first frame is rendered. In you situation it is never resolved because applyLens is never called. And applyLens is never called, because the session is null. And the session is null because setSession is never called. You see the circular dependency here...
0 -
I think I was wrong regarding blocking play(). Example here proofs that it is not blocking: https://docs.snap.com/camera-kit/guides/tutorials/web-tutorials/camera-kit-web-for-beginners#4-putting-it-all-together
I wonder maybe your component is re-mounted multiple times due to React business? When I try your component as a top level one, I don't see any issue... Make sure bootstrapCameraKit is called once for lifetime of your page. You could use react contexts for that.
1