callObject.join throws a "Cannot read properties of null (reading 'start')" exception
Hey all - i have a recoil app that hoists the DailyProvider in two files. The first is main.jsx
, which loads the RecoilRoot inside a Meteor startup:
import React from 'react' import { Meteor } from 'meteor/meteor' import { render } from 'react-dom' import { RecoilRoot } from 'recoil' import App from '../imports/ui/App' Meteor.startup(() => { render( <RecoilRoot> <App /> </RecoilRoot>, document.getElementById('react-target') ) })
Next, the App.jsx
loads the DailyProvider
like this:
import React from 'react' import { BrowserRouter as Router } from 'react-router-dom' import DailyIframe from '@daily-co/daily-js' import { useSetRecoilState } from 'recoil' import { DailyProvider } from '@daily-co/daily-react' import { callObj } from './recoil/atoms' import Main from './Main' export default function App() { const callOpts = { dailyConfig: { v2CamAndMic: true, }, } const setCallObj = useSetRecoilState(callObj) const co = DailyIframe.createCallObject(callOpts) setCallObj(co) return ( <DailyProvider callObject={co} recoilRootProps={{ // stores Daily React's state in RecoilRoot above override: false, }} > <Router> <Main /> </Router> </DailyProvider> ) }
And finally, when I make this call deeper in the app:
const callObject = useRecoilValue(callObj)
const joinResult = await callObject.join({ url: `${BASE_DAILY_URL}/${roomId}`, token: joinToken, })
And I am getting the below exception from the daily library:
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'start')
at e.value (modules.js?hash=5af7ca3d8ce672432ea2e8d9a93c030b0148f7ab:50669:16116)
at modules.js?hash=5af7ca3d8ce672432ea2e8d9a93c030b0148f7ab:50669:79332
at new Promise (<anonymous>)
at z.<anonymous> (modules.js?hash=5af7ca3d8ce672432ea2e8d9a93c030b0148f7ab:50669:79256)
at Generator.next (<anonymous>)
at t (modules.js?hash=5af7ca3d8ce672432ea2e8d9a93c030b0148f7ab:50663:3742)
at s (modules.js?hash=5af7ca3d8ce672432ea2e8d9a93c030b0148f7ab:50663:3945)
at modules.js?hash=5af7ca3d8ce672432ea2e8d9a93c030b0148f7ab:50663:4004
at new Promise (<anonymous>)
at z.<anonymous> (modules.js?hash=5af7ca3d8ce672432ea2e8d9a93c030b0148f7ab:50663:3885)
the object on which start
is being called is on this line:
this._currentLoad.start()
When I didn't store the callObject in recoil, and I created it in the same file as the callObject.join call, then this exception wasn't throwing. The problem is I'm trying to use the callObject elsewhere. Whether using useDaily
or useRecoilValue(callObj)
doesn't seem to matter - this exception is always being thrown.
Any ideas?? Thanks!
Best Answer
-
@zarally Daily React internally stores the
callObject
in a React state usinguseState()
and passes it down to other components through a React context. Have you considered storing your own callObject in a React state instead of a recoil atom? It's possible that a callObject instance doesn't match all requirements for a recoil atom, because the callObject is not immutable. If you need to store it in an atom, you could try setting thedangerouslyAllowMutability
flag on the atom, but otherwise I'd recommend storing it in a simple React state, as it's proven to work in Daily React internally, and access the instance withuseDaily()
inside of your application.Let me know if that helps!
0
Answers
-
Hey @zarally,
I'm not super familiar with Meteor, but looking at the provided code through a React lens, I would highly suggest to not create the
callObject
as part of the render phase in theApp
component.Instead you'll want to create it inside of a
useEffect
and instead of passing the "just created reference to the call object" toDailyProvider
, you'll probably want to pass the recoil value.Here's a suggested update to your App component:
import React, { useEffect } from 'react' import { BrowserRouter as Router } from 'react-router-dom' import DailyIframe from '@daily-co/daily-js' import { useRecoilValue, useSetRecoilState } from 'recoil' import { DailyProvider } from '@daily-co/daily-react' import { callObj } from './recoil/atoms' import Main from './Main' const callOpts = { dailyConfig: { v2CamAndMic: true, }, } export default function App() { const co = useRecoilValue(callObj); const setCallObj = useSetRecoilState(callObj); // Initialize useEffect(() ⇒ { // callObject already created and stored in Recoil if (co) return; // Check if callObject was already created let _co = DailyIframe.getCallInstance(); if (!_co) { // Create callObject if necessary _co = DailyIframe.createCallObject(callOpts); } // Store callObject in Recoil setCallObj(_co); }, [co, setCallObj]); return ( <DailyProvider callObject={co} recoilRootProps={{ // stores Daily React's state in RecoilRoot above override: false, }} > <Router> <Main /> </Router> </DailyProvider> ) }
Let me know if this improves the situation for you!
1 -
Thanks! I will try this. In the interim I did end up having to put the callObj on
window
and not in recoil, which is suboptimal.0 -
I tried the same <App> configuration you suggested (in the useEffect hook but not in the render), but unfortunately that throws the same error.
"@daily-co/daily-js": "^0.50.0", "@daily-co/daily-react": "^0.11.6",
I'm tried using both
const callObject = useRecoilValue(callObj)
andconst callObject = useDaily()
— both work to retrieve the callObject, but neither work when I attempt tojoin
the room, throwing the above error.I've tried with and without
v2CamAndMic: true
and it doesn't seem to matter.Instead, if I assign callObject to window in the <App> —
window.callObject = callObj
then usewindow.callObject.join
— it joins the room without throwing the exception…0 -
Interestingly, calling
setCallObj(_co);
is what seems to mess up the object - I pass it by reference to the global objectwindow.callObject = _co
— and the join call only works if I do NOTsetCallObj(_co)
first. (I realize i wouldn't need to save the callObject in both places, I was just trying to discover what causes the object to be unable to make the join call)0 -
Hi @christian - that worked, thanks! I was able to use store the callObject in just the React.state, NOT in recoil, as you're suggesting. I did have to remove the below as well. Seems like it should be documented for now — using this in the
<DailyProvider>
seems misleading, as it can't truly story the callObject in recoil.recoilRootProps={{ // stores Daily React's state in RecoilRoot above override: false, }}
Thanks so much for your help.
3