Socket notifications

223 views Asked by At

I have a screen that receives notifications from the Spring Boot backend, and I show them in a bell. When deleting a notification it deletes it well, but when another new notification arrives it loads the ones that I had already deleted.

import SockJS from 'sockjs-client'; 
import Stomp from 'stompjs';

// core components

const HeaderNotificacions = () => {

const [chipData, setChipData] = useState([]); //Hook where I load the notifications that come from the backend    > 

const historyAlerts = localStorage.getItem('notys')
 ? JSON.parse(localStorage.getItem('notys'))
 : [];   if (chipData.length === 0 && historyAlerts.length !== 0) { //I get the notifcations when I reload the browser
 setChipData(historyAlerts);   }

useEffect(() => {


 var sock = new SockJS(
   `${process.env.REACT_APP_WEB_SOCKET}mocaConsola/api/notifications`
 );
 let stompClient = Stomp.over(sock);
 sock.onopen = function () {
   /*    console.log('open'); */
 };
 stompClient.connect({}, function (frame) {
   stompClient.subscribe('/ws/alertNotification', function (greeting) {
     if (stompClient !== null) {
       stompClient.disconnect();
     }

     setChipData([
       ...chipData,
       {
         key: greeting.headers['message-id'],
         label: JSON.parse(greeting.body).content,
       },
     ]);
   });
 });   }, [chipData]);

localStorage.setItem('notys', JSON.stringify(chipData));

const handleDelete = (chipToDelete) => () => {
 const historyAlerts = localStorage.getItem('notys')  //function to delete a notification
   ? JSON.parse(localStorage.getItem('notys'))            
   : [];

 setChipData((chips) =>
   chips.filter((chip) => chip.key !== chipToDelete.key)
 );

 const local = historyAlerts.filter((chip) => chip.key !== chipToDelete.key);
 localStorage.setItem('notys', JSON.stringify(local));   };
1

There are 1 answers

0
udalmik On

One of the problems could be that you do not disconnect from the socket, so first subscription (having initial value of chipData in closure) brings it back. Unsubscribing on effect's clean up could help, similar to:

useEffect(() => {
   
/* your code */      

>     stompClient.connect({}, function (frame) {
>       subscription = stompClient.subscribe('/ws/alertNotification', function (greeting) {
>         if (stompClient !== null) {
>           stompClient.disconnect();
>         }
> 
>         setChipData([
>           ...chipData,
>           {
>             key: greeting.headers['message-id'],
>             label: JSON.parse(greeting.body).content,
>           },
>         ]);
>       });
>     });  
   
   return () => subscription && subscription.unsubscribe();
}, [chipData]);

Also for performance considerations we can skip recreation of the connection/subscription each time we update chipData. We can use callback version of setChipData's argument which refer to latest value of state.

setChipData(prevData => [
>           ...prevData,
>           {
>             key: greeting.headers['message-id'],
>             label: JSON.parse(greeting.body).content,
>           },
>         ]);

so we can replace [chipData] to [] as second argument of useEffect and open connection only once per component load.