How to import SignalR in React Component?

落花浮王杯 提交于 2020-06-22 19:35:26

问题


I have used create-react-app to scaffold the initial react application.

My DashBoard component:

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import $ from 'jquery';
import 'signalr';

class Dashboard extends Component {
   constructor(props) {    
   super(props);
   var connection = $.hubConnection('http://[address]:[port]');
   var proxy = connection.createHubProxy('[hubname]');   

    // atempt connection, and handle errors
    connection.start()
    .done(function(){ console.log('Now connected, connection ID=' + connection.id); })
    .fail(function(){ console.log('Could not connect'); });
}

  render() {
    return (...);
  }
}

export default Dashboard;

Now I get the below error from SignalR saying jQuery is not added, but I have imported it in the line above:

Error: jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.

If I comment out import "signalr"; jQuery gets loaded correctly and i can access the $ inside the module. Why does this happen?


回答1:


UPDATE: Please note that if you are using Redux in your ReactJS app, the solution below is not necessarily the best solution. It is better to implement signalR as a middleware. You can find the best answer here.

If you are not using Redux, or you still want to implement it in a React component, then read on: For people that are using the latest version of signalR (core v2.1), since jQuery is not a dependency of signalR any more, you can import it like:

import * as signalR from '@aspnet/signalr';

NOTE: there is now a newer version of signalr available (@microsoft/signalr) that requires a different setup. This solution only works with @aspnet/signalr. (UPDATE June 2020)

And then use it like:

signalR.HubConnectionBuilder()

Here is an example:

import React, { PureComponent } from 'react';
import { string } from 'prop-types';
import * as signalR from '@aspnet/signalr';

class SignalR extends PureComponent {
  constructor (props) {
    super(props);

    this.connection = null;
    this.onNotifReceived = this.onNotifReceived.bind(this);
  }

  componentDidMount () {
    const protocol = new signalR.JsonHubProtocol();

    const transport = signalR.HttpTransportType.WebSockets;

    const options = {
      transport,
      logMessageContent: true,
      logger: signalR.LogLevel.Trace,
      accessTokenFactory: () => this.props.accessToken,
    };

    // create the connection instance
    this.connection = new signalR.HubConnectionBuilder()
      .withUrl(this.props.connectionHub, options)
      .withHubProtocol(protocol)
      .build();

    this.connection.on('DatabaseOperation', this.onNotifReceived);
    this.connection.on('DownloadSession', this.onNotifReceived);
    this.connection.on('UploadSession', this.onNotifReceived);

    this.connection.start()
      .then(() => console.info('SignalR Connected'))
      .catch(err => console.error('SignalR Connection Error: ', err));
  }

  componentWillUnmount () {
    this.connection.stop();
  }

  onNotifReceived (res) {
    console.info('Yayyyyy, I just received a notification!!!', res);
  }

  render () {
    return <span />;
  };
};

SignalR.propTypes = {
  connectionHub: string.isRequired,
  accessToken: string.isRequired
};

export default SignalR;

UPDATE: in 2020, you can use "withAutomaticReconnect()":

  const connection = new HubConnectionBuilder()
    .withUrl(connectionHub, options)
    .withAutomaticReconnect()
    .withHubProtocol(new JsonHubProtocol())
    .configureLogging(LogLevel.Information)
    .build();



回答2:


What I figured out Signalr has dependency on jQuery. For some reason import $ from 'jquery' doesn't set window.jQuery. That's why need to do it explicitly.

I solved the issue this way:

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import $ from 'jquery';
window.jQuery = $;
require('signalr');

class Dashboard extends Component {
   // .....   
}

export default Dashboard;



回答3:


Check out SignalR no jQuery

npm i -D signalr-no-jquery
import { hubConnection } from 'signalr-no-jquery';

const connection = hubConnection('http://[address]:[port]', options);
const hubProxy = connection.createHubProxy('hubNameString');

// set up event listeners i.e. for incoming "message" event
hubProxy.on('message', function(message) {
    console.log(message);
});

// connect
connection.start({ jsonp: true })
  .done(function(){ console.log('Now connected, connection ID=' + connection.id); })
  .fail(function(){ console.log('Could not connect'); });

https://www.npmjs.com/package/signalr-no-jquery




回答4:


This is how we do it now (year 2020) with the new package @microsoft/signalr. We use Redux, but you don't have to use Redux to be able to utilize this method.

If you are using @microsoft/signalr package instead of @aspnet/signalr, then this is how you can set it up. This is our working code in prod:

import {
  JsonHubProtocol,
  HubConnectionState,
  HubConnectionBuilder,
  LogLevel
} from '@microsoft/signalr';

const isDev = process.env.NODE_ENV === 'development';

const startSignalRConnection = async connection => {
  try {
    await connection.start();
    console.assert(connection.state === HubConnectionState.Connected);
    console.log('SignalR connection established');
  } catch (err) {
    console.assert(connection.state === HubConnectionState.Disconnected);
    console.error('SignalR Connection Error: ', err);
    setTimeout(() => startSignalRConnection(connection), 5000);
  }
};

// Set up a SignalR connection to the specified hub URL, and actionEventMap.
// actionEventMap should be an object mapping event names, to eventHandlers that will
// be dispatched with the message body.
export const setupSignalRConnection = (connectionHub, actionEventMap = {}, getAccessToken) => (dispatch, getState) => {
  const options = {
    logMessageContent: isDev,
    logger: isDev ? LogLevel.Warning : LogLevel.Error,
    accessTokenFactory: () => getAccessToken(getState())
  };
  // create the connection instance
  // withAutomaticReconnect will automatically try to reconnect
  // and generate a new socket connection if needed
  const connection = new HubConnectionBuilder()
    .withUrl(connectionHub, options)
    .withAutomaticReconnect()
    .withHubProtocol(new JsonHubProtocol())
    .configureLogging(LogLevel.Information)
    .build();

  // Note: to keep the connection open the serverTimeout should be
  // larger than the KeepAlive value that is set on the server
  // keepAliveIntervalInMilliseconds default is 15000 and we are using default
  // serverTimeoutInMilliseconds default is 30000 and we are using 60000 set below
  connection.serverTimeoutInMilliseconds = 60000;

  // re-establish the connection if connection dropped
  connection.onclose(error => {
    console.assert(connection.state === HubConnectionState.Disconnected);
    console.log('Connection closed due to error. Try refreshing this page to restart the connection', error);
  });

  connection.onreconnecting(error => {
    console.assert(connection.state === HubConnectionState.Reconnecting);
    console.log('Connection lost due to error. Reconnecting.', error);
  });

  connection.onreconnected(connectionId => {
    console.assert(connection.state === HubConnectionState.Connected);
    console.log('Connection reestablished. Connected with connectionId', connectionId);
  });

  startSignalRConnection(connection);

  connection.on('OnEvent', res => {
    const eventHandler = actionEventMap[res.eventType];
    eventHandler && dispatch(eventHandler(res));
  });

  return connection;
};

Then you would call like the following. Please note that this a pseudo code. You may have to call it differently depending on your project setup.

import { setupSignalRConnection } from 'fileAbove.js';

const connectionHub = '/hub/service/url/events';

export const setupEventsHub = setupSignalRConnection(connectionHub, {
  onMessageEvent: someMethod
}, getAccessToken);

export default () => dispatch => {
  dispatch(setupEventsHub); // dispatch is coming from Redux
};

Let me know if it helped by up-voting. Thank you



来源:https://stackoverflow.com/questions/46190574/how-to-import-signalr-in-react-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!