Joey Coder
Joey Coder

Reputation: 3529

Rendering iFrame in React

I have a parent component with two buttons. Button 1 should open iFrame with url 1 and button 2 url 2. It seems the way I built it the iFrame is not rebuilt entirely.

parent.js

if (currentTable.id === "Bo3Ko3K") {
    <DailyCo url="https://meeting.daily.co/123456" />
} else if (currentTable.id === "9RGmWxX") {
    <DailyCo url="https://meeting.daily.co/abcdef" />
}

child.js

import { makeStyles } from "@material-ui/core/styles";
import React, { useRef, useEffect } from "react";
import DailyIframe from "@daily-co/daily-js";

const useStyles = makeStyles((theme) => ({
  root: {
    width: "100%",
    height: "100vh",
    border: "0",
  },
}));

const DailyCo = ({ url }) => {
  const classes = useStyles();
  const iframeRef = useRef();

  useEffect(() => {
    if (!url) {
      console.error("please set an url!");
      return;
    }
    const daily = DailyIframe.wrap(iframeRef.current, {
      // showLeaveButton: true,
    });
    daily.join({ url });
  }, [url]);

  return (
    <iframe
      className={classes.root}
      title="video call iframe"
      ref={iframeRef}
      allow="camera; microphone; fullscreen"
    ></iframe>
  );
};

export default DailyCo;

Upvotes: 0

Views: 1199

Answers (1)

Zachary Haber
Zachary Haber

Reputation: 11037

You have 2 options I can see to get this working:

  1. You need to leave the meeting before joining a new one. Unfortunately this method is complicated by daily taking about 7ms (in an async manner) to leave a meeting. So, it isn't possible to just have the useEffect clean up normally. It's also fun because daily.leave() returns a promise that never resolves if you aren't in a meeting. Their documentation for leave() is currently misleading:

Leaves the meeting. If there is no meeting, this method does nothing.

Returns null;

https://codesandbox.io/s/reverent-grass-qpjke?file=/src/App.js

  const iframeRef = useRef();
  const dailyRef = useRef();
  const joinedRef = useRef();
  useEffect(() => {
    dailyRef.current = DailyIframe.wrap(iframeRef.current, {
      // showLeaveButton: true,
    });
    dailyRef.current.on('left-meeting',()=>{
      joinedRef.current=false;
    })
    dailyRef.current.on('joining-meeting',()=>{
      joinedRef.current=true
    })
    console.log("mounted");
    return () => {
      dailyRef.current.destroy();
      console.log("unmount");
    };
  }, []);
  useEffect(() => {
    (async () => {
      if (joinedRef.current) {
        // This is needed due to it never returning
        // if there wasn't a meeting joined first...
        await dailyRef.current.leave();
      }
      if (!url) {
        console.error("please set an url!");
        return;
      }
      await dailyRef.current.join({ url });
    })();
  }, [url]);

  1. You need to call daily.destroy() before creating a new Wrap, otherwise they interfere with each other and issues abound and the new one never fully sets up. This issue is described in their documentation for destroy

You can re-use the daily-js call iframe or call object multiple times (a sequence of join(), leave(), join(), etc method calls will work fine).

But when you are finished with the daily-js call object, you should call destroy() to free all resources associated with it.

This is particularly important if you plan to create another daily-js object in the future. If you don't call destroy(), and later create a new daily-js call object, the event listeners from the old object and the new object will interfere with one another.

https://codesandbox.io/s/spring-water-nv3k3?file=/src/App.js

  const iframeRef = useRef(null);
  useEffect(() => {
    if (!url) {
      console.error("please set an url!");
      return;
    }
    const daily = DailyIframe.wrap(iframeRef.current, {
      // showLeaveButton: true,
    });
    daily.join({ url });
    return () => {
      daily.destroy();
    };
  }, [url]);

In general, I'd recommend to use option 1 if only because it's more performant (less set up and time required to change meetings). Even though it's easier to just destroy the wrap and recreate it.

Upvotes: 1

Related Questions