blackuy / react-native-twilio-video-webrtc

Twilio Video (WebRTC) for React Native
https://www.twilio.com/docs/video
MIT License
609 stars 403 forks source link

Odd errors when using React.forwardRef to TwilioVideo component #504

Open kieran-osgood opened 3 years ago

kieran-osgood commented 3 years ago

So to preface this, I've successfully setup and used TwilioVideo for a call between multiple devices, so I'm certain we're installed correctly etc. I'm now trying to wrap the TwilioVideo component with a HOC and forward the ref on to provide a more composable component for our project.

Steps to reproduce

I'll first give an example using a basic react-native button which works as I'd expect, and then what fails with the TwilioVideo component.

Working as expected:

type ForwardedButtonProps = {} & ButtonProps
export const ForwardedButton = React.forwardRef<Button, ForwardedButtonProps>(
  ({ title = "Press Me", onPress: onPressCallback, ...rest }, ref) => {
    const onPress = (e) => {
      console.log(ref?.current)
      onPressCallback(e)
    }

    return (
      <Button {...rest} {...{ ref, title, onPress }}>
        cmon
      </Button>
    )
  },
)
ForwardedButton.displayName = "ForwardedButton"

In the above example, when I log out the ref.current in the onPress I get back the value of the button element - great! I even tried double wrapping incase it was a thing I wasn't aware of about forwarding on a forwarded ref or something:

Also working as expected:

type DoubleForwardedButtonProps = {} & ButtonProps
export const DoubleForwardedButton = React.forwardRef<Button, DoubleForwardedButtonProps>(
  ({ title = "Press Me", onPress: onPressCallback, ...rest }, ref) => {
    const onPress = (e) => {
      console.log(ref?.current)
      onPressCallback(e)
    }

    return <ForwardedButton {...rest} {...{ ref, title, onPress }} />
  },
)
DoubleForwardedButton.displayName = "DoubleForwardedButton"

And this still works, however when I try to use this same structure with the TwilioVideo component, I get the weirdest error because it doesn't seem to be related to the TwilioVideo component but also it's only when I'm doing it with this component I can replicate it? So here's what I'm doing: Broken:

export const VideoCallContainer = React.forwardRef<TwilioVideo, VideoCallContainerProps>(
  (props, ref) => {
    console.tron.log('ref: ', ref)
    const { token, children } = props

    const videoTracks = new Map()
    const status: VideoCallStatus = "DISCONNECTED"

    const connect = () => {
      ref.current?.connect({ accessToken: token })
    }

    const value = { token, videoTracks, status }
    return (
      <>
        <VideoCallContext.Provider {...{ value }}>
          {children}
          <TwilioVideo ref={ref} />
        </VideoCallContext.Provider>
      </>
    )
  },
)
VideoCallContainer.displayName = "VideoCallContainer"

the error is: [Thu Jun 17 2021 06:26:49.672] ERROR Error: Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started for setup instructions.

I know this seems to suggest the error is in react-navigation, but I am certain my react-navigation is setup correctly as I am within a screen, I am using the useNavigation and useRoute hooks within it with no problems etc., the error only occurs when accessing the ref I am passing to TwilioVideo component.

To clarify - the ref causes an error both within the HOC component or at the the parent where I'm instantiating the VideoCallContainer component/the ref thats passed down - both will throw this error the moment I try to access it in any way (even just a simple console.log(twilioRef) will throw this error.

I hope I'm just doing something stupid here but I can't see a difference in the way I'm doing things - any help would be greatly appreciated, thanks.

Environment

react-native-twilio-video-webrtc

Version: 2.0.0

slycoder commented 3 years ago

Ok, I have a couple of guesses. But just to clarify, do you get the error when things are mounted or when performing an operation (i.e. calling connect)?

kieran-osgood commented 3 years ago

@slycoder So I tried to demo it in the snippets I posted, it doesn't happen on mount, however it doesn't even need to be calling something on the instance like connect, just trying to log out the ref object (not the ref.current, or ref.current.connect) will cause the error e.g. console.log(twilioRef)

slycoder commented 3 years ago

I guess I never did respond. So I'm not super sure what the underlying cause is but my guess at the time (which might still be correct) is that because there are no .binds in the wrapper component, that somehow in one of the lifecycles this is set to some calling context of the react navigation component.