robtaussig / react-use-websocket

React Hook for WebSocket communication
MIT License
1.63k stars 135 forks source link

Property EventSource does not exist #85

Closed DZuz14 closed 3 years ago

DZuz14 commented 3 years ago

Description

Upgrading from version 2.5.0 to 2.6.1 results in a red screen of death in React Native, with the error, "Property EventSource does not exist". Version 2.5.0 works just fine, and I have not tested version 2.6.0.

System Info

System:
    OS: Windows 10 10.0.19042
    CPU: (8) x64 Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz        
    Memory: 4.82 GB / 15.92 GB
  Binaries:
    Node: 12.18.2 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.4 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 6.11.3 - C:\Program Files\nodejs\npm.CMD
    Watchman: Not Found
  SDKs:
    Android SDK:
      API Levels: 28, 29, 30
      Build Tools: 28.0.3, 29.0.2, 30.0.2
      System Images: android-29 | Google Play Intel x86 Atom, android-30 | Google APIs Intel x86 Atom_64
      Android NDK: Not Found
    Windows SDK: Not Found
  IDEs:
    Android Studio: Version  4.0.0.0 AI-193.6911.18.40.6626763   
    Visual Studio: 15.9.28307.1064 (Visual Studio Community 2017)  Languages:
    Java: 1.8.0_211
    Python: 3.8.3
  npmPackages:
    @react-native-community/cli: Not Found
    react: ^17.0.0 => 17.0.2
    react-native: 0.62.2 => 0.62.2
    react-native-windows: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Screenshot_1621268793

robtaussig commented 3 years ago

Hi @DZuz14,

Thank you for bringing this to my attention -- I am not experienced with React Native, but it looks like React Native does not support EventSource api out of the box, but cursory research suggests this might be fixable with a polyfill:

https://github.com/jordanbyron/react-native-event-source

If you wouldn't mind, could you see whether installing react-native-event-source and importing it before this library fixes your issue? I'm not sure whether I'd rather fix this with a polyfill (which would require adding a dependency) or adding checks in the code to prevent this error (but then not support EventSource in React Native), but before I consider my options, I would like to confirm the underlying issue.

DZuz14 commented 3 years ago

@robtaussig Thank you very much for your response! I will give installing that package a shot and let you know.

DZuz14 commented 3 years ago

@robtaussig After checking out the code for react-native-event-source, it doesn't look like importing this package before react-use-websocket will have an effect.

Checking the index.js file, this file exports a class named RNEventSource, in which an EventSource is instantiated within it's constructor. Importing this package doesn't produce a global EventSource that could be accessed by react-use-websocket

robtaussig commented 3 years ago

I see -- apologies for wasting your time. I had assumed from their example that it was polyfilling EventSource, but likely just a mistake in their documentation and they mean to instantiate RNEventSource:

import React, { Component } from 'react';
import { View, Text } from 'react-native';

import RNEventSource from 'react-native-event-source';

class MyApp extends Component {
  componentDidMount() {
    this.eventSource = new EventSource('https://sse.com/stream');

    // Grab all events with the type of 'message'
    this.eventSource.addEventListener('message', (data) => {
      console.log(data.type); // message
      console.log(data.data);
    });
  }
  componentWillUnmount() {
    this.eventSource.removeAllListeners();
    this.eventSource.close();
  }
  render() {
    return (
      <View>
        <Text>Streaming!</Text>
      </View>
    )
  }
}

For now, I'll add guards against this error, without supporting EventSource for react-native, since EventSource support is not a high priority for this library. Thanks again for your issue!

robtaussig commented 3 years ago

@DZuz14,

Not being familiar with React Native, I don't want to assume anything, but would the following be a reasonable runtime guard?

  const isEventSourceSupported = 'EventSource' in window;

  //In code
  if (isEventSourceSupported) {
    //Access window.EventSource
  }
robtaussig commented 3 years ago

Thanks, that's what I was worrying about. I'll do a bit of research myself, but will defer to any ideas you come up with.

robtaussig commented 3 years ago

Based on this, it looks like I can use:

  const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
  const isEventSourceSupported = !isReactNative && 'EventSource' in window;

Thoughts?

DZuz14 commented 3 years ago

That looks like it works perfectly!

DZuz14 commented 3 years ago

Thank you for the quick responses and the package as a whole. I'll await an updated release to see if that fixes everything.

robtaussig commented 3 years ago

Hi @DZuz14,

Pushed out a fix and bumped library version to 2.7.0. Let me know how it works for you!

201a922f00e43510e1ec7c08ef751ff36d4e817e

DZuz14 commented 3 years ago

@robtaussig I can confirm that the fix works. My app is now utilizing 2.7.0.

robtaussig commented 3 years ago

Excellent -- thank you for your report and for your time in helping me resolve this.