0

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!

Claim0013
  • 421
  • 2
  • 9
  • 24
  • did you try using an arrow function for the callback in the stompClient.connect method? Either that or you could bind the refresh tanks to this using this.refetchTanks = this.refetchTanks.bind(this); in your component's constructor – Jay Lane Feb 22 '18 at 14:17
  • Yeah I tried that. I was getting a "property refetchTanks() of this is undefined". I just couldn't access class methods. – Claim0013 Feb 23 '18 at 07:08
  • Where are you importing `SockJS` from? – Francisco Souza Oct 15 '19 at 10:48

2 Answers2

2

I know, it is a bit old question, but since it pops every time when you search for stomp issue, i thought of answering it. The way to access this in callbacks is to bind callbacks with this first, then the whole of object can be accessed in the callback. Example:

    connectCallBack(){
  this.setState({loading:false})

 }
 errorCallback=()=>{

 }

componentDidMount() {


axios.post('http://localhost:8080/subscribe', null, { params: {
deviceId
}})
.then(response => response.status)
.catch(err => console.warn(err));

const socket = new SockJS('http://localhost:8080/test');
const stompClient = Stomp.over(socket);

//stompClient.connect();
stompClient.connect( {}, this.connectCallBack, this.errorCallback);

If see above code both callbacks can access this.

samairtimer
  • 706
  • 1
  • 11
  • 23
  • Thanks for taking your time! I haven't thought about passing functions as params. – Claim0013 Mar 04 '20 at 14:17
  • my code is stompClient.connect({}, (frame) => { console.log('Connected: ' + frame); stompClient.subscribe('/user/api/getChat', (messageOutput) =>{ // this.connectCallBack.bind(this); console.log(JSON.parse(messageOutput.body).message); var mymessage =JSON.parse(messageOutput.body).message; this.state = { incomingchatMessage: [], chatMessages:[] } }); }); but not able to refresh it . what to do ? – Anuj May 06 '20 at 20:38
1

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!

Claim0013
  • 421
  • 2
  • 9
  • 24