0

So, I've basically tried everything with this one. I ran out of solutions or options. Thing is, I have a button. When you click on it your camera will open and you will see some filters that you can apply to your face. I am new to React. Made it work without the iframe to test the API first, but it's not working anymore inside this iframe. The react component needs to be inside this iframe. The code can be found here with what I did so far/tried: https://codesandbox.io/s/cool-fog-3k5si5?file=/src/components/button/button.jsx

The problem is that when I click the button, the canvas disappears from the page and I get this error in the console: enter image description here

The DeepAR API fails initialization because the canvas is no longer on the page and it crashes. I really don't know what to search for as I considered this to be a react render error and I tried different ways to write the react code (functional/class). If you have any ideas or suggestions, please help. Thank you in advance.

  • The code seems to not be running. In any case, the error message indicates React took something out of the DOM. Note that if you create something conditionally inside the code of a React component (before the return <…), it is evaluated _on each render_, probably not what you want. And showing/hiding with { testexpression && } can also cause mount/unmounts you didn't expect. – Arno Teigseth Nov 01 '22 at 22:11
  • So I cannot get it work 100% but one of your problems is that you are using useEffect hook incorrectly. In the useEffect hook whatever you write will be executed whenever a dependency changes, however you can also return a cleanup function which will be executed only when the components rerenders. In your case you want your fetch request to be executed when the component mounts but you have put it inside the cleanup function and your fetch code is not being executed. Can you check if this fixes the issue – Besnik Korça Nov 02 '22 at 13:39
  • Changing the useEffect to this - basically you have to remove the wrapping return function in the useEffect `useEffect(() => { fetch( "https://cors-anywhere.herokuapp.com/https://staging1.farmec.ro/rest/V1/farmec/deeparProducts/" ) .then((response) => response.json()) .then((productsJson) => setProducts(productsJson)) }, []);` beyond that the fetch request is failing for me due to a cors issue related to cors-everywhere, are you running into the same thing? – Besnik Korça Nov 02 '22 at 13:40

1 Answers1

0

Your use of useEffect in your Modal and App Component is incorrect.

To remind you, useEffect accepts a function which runs after the render is committed to the screen. If the function returns a function (which is your case), this function is the "clean up" function which is run before the component is removed from the UI.

So what is happening is that your useEffect code is run only when your components are being unmounted.

Since we are not concerned with any clean up at this stage, a quick solution for you is to move the clean up expressions to the main effect function as follows:

useEffect(() => {
    fetch(
      "https://cors-anywhere.herokuapp.com/https://staging1.farmec.ro/rest/V1/farmec/deeparProducts/"
    )
      .then((response) => response.json())
      .then((productsJson) => setProducts(productsJson));
}, []);

The same goes for your Modal component :

useEffect(() => {
    let initializedDeepAR = new DeepAR({
      licenseKey:
        "6fda241c565744899d3ea574dc08a18ce3860d219aeb6de4b2d23437d7b6dcfcd79941dffe0e57f0",
      libPath: DeepAR,
      deeparWasmPath: deeparWasm,
      canvas: canvas.current,
      segmentationConfig: {
        modelPath: segmentationMode
      },
      callbacks: {
        onInitialize: () => {
          // let filterName = colors[0].filterData[0]['Filter Binary Path'].match(new RegExp("[^/]+(?=\\.[^/.]*$)"))[0];
          setDeepAR(initializedDeepAR);
          initializedDeepAR.startVideo(true);
          // initializedDeepAR.switchEffect(0, 'slot', `https://staging1.farmec.ro/media/deepArFilters/${filterName}.bin`);
        }
      }
    });

    /*@TODO: replace paths with server local path*/
    initializedDeepAR.downloadFaceTrackingModel(models);
}, []);

With one additional fix concerning your use of useRef.

To target the element behind the useRef, you must use the .current property.

Finally, your Frame component is using useState to manage the mounting of the iframe. I would suggest using the useRef hook with a useState for your mountNode as follows:

export const Frame = ({
                        children,
                        styleSelector,
                        title,
                        ...props
                      }) => {
  const contentRef = useRef(null)
  const [mountNode, setMountNode] = useState()

  useEffect(() => {
    setMountNode(contentRef.current.contentWindow.document.body)
  }, [])
  
  useEffect(() => {
    const win = contentRef.current.contentWindow
    const linkEls = win.parent.document.querySelectorAll(
      styleSelector
    )
    if (linkEls.length) {
      linkEls.forEach((el) => {
        win.document.head.appendChild(el)
      })
    }
  }, [styleSelector])

  return (
    <iframe title={title} {...props} ref={contentRef}>
      {mountNode && createPortal(children, mountNode)}
    </iframe>
  )
}
mlegrix
  • 799
  • 5
  • 12