Search code examples
reactjsspring-bootwebsocketspring-websocketweb-stomp

Can't use "this" in stomp client subscribe - React


I have my Spring-Boot service setup so I can send messages through websocket to my browser and it works.

  //@MessageMapping
    @RequestMapping(value = "/notify")
    @SubscribeMapping("/notification")
    @SendTo("/topic/notification")
    public String sendNotification() throws Exception {
        sendMessage();
        return "Request to update Tanks has been sent!";
    }

    public void sendMessage() {
        this.messagingTemplate.convertAndSend("/topic/notification", "IT WORKS");
    }

Here's the console log from chrome:

<<< MESSAGE
destination:/topic/notification
content-type:text/plain;charset=UTF-8
subscription:sub-1519225601109-13
message-id:f2qodiqn-8
content-length:8

IT WORKS

I want to be able to receive a message from the service and update the state in react, so, that it refetches from the backend. This is what my client looks like:

var socket = new SockJS("http://localhost:6667/refresh");
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
  console.log('connected: ' + frame);
  stompClient.subscribe('/topic/notification', function(notification){
    console.log(notification.body);
    //this.showNotification(JSON.parse(notification.body).content);
    //this.showNotification(notification.body);
  })
}, function(err) {
  console.log('err', err);
});

And the fetch in componentDidMount()

fetch(`http://localhost:6666/front/objects`)
    .then(result=>result.json())
    .then(fuelTanks=>this.setState({fuelTanks}))
    .catch(function(err) {
      console.log('Could not fetch: ' + err.message);
    }
  )

I can't use this.showNotification(notification.body), hence I can't set the state to be able to refetch my objects. I tried making methods outside the class but then I can't use anything from the main class.

Is there a way to make react run componentDidMount again, or better, just access the fetch method in my class when I get a message from spring through the websocket?

Like this:

componentDidMount(){

  var socket = new SockJS("http://192.168.1.139:8610/refresh");
  var stompClient = Stomp.over(socket);
  stompClient.connect({}, function(frame) {
    console.log('connected: ' + frame);
    stompClient.subscribe('/topic/notification', function(notification){
      refetchTanks(); // call fetch tanks -> can't use "this"
    })
  }, function(err) {
    console.log('err', err);
  });

Thanks!


Solution

  • I tried everything to be able to use my class methods and the state in stompClient's .subscribe method. I was able to connect and reconnect if the service died, nevertheless it wasn't working.

    I decided to use react-stomp, which worked. I could use a class method in onMessage=.... This is what my code looks like:

    <SockJsClient 
      url = 'http://localhost:8610/refresh/'
      topics={['/topic/notification']} 
      onConnect={console.log("Connection established!")} 
      onDisconnect={console.log("Disconnected!")}
      onMessage={() => this.update()}  <------ this method performs a new GET 
                                               request
      debug= {true}
    /> 
    

    I also had to send the message in a specific way on the server side, since I was getting a JSON error when sending a string.

    this.messagingTemplate.send("/topic/notification", "{"text":"text"}");
    
    <<< MESSAGE
    destination:/topic/notification
    content-type:text/plain;charset=UTF-8
    subscription:sub-0
    message-id:aaylfxl4-1
    content-length:49
    
    {
    
      "text": "text"
    
    }
    

    It currently works, but I am curious if there are other, better solutions to this issue.

    EDIT: a much better solution here! Use the code from the first post and create a variable before connect to be able to access this like this var self = this;, then just access is as self.update() after subscribe!