How To Listen WebSocket Messages And Pops Up In Real Time Example Code

This article mainly introduces the front-end example code that can listen to WebSocket messages and pops up in real-time. This example assumes that you have mastered the react js and are familiar with umiJS.

1. Project Requirements.

  1. The server side pushes messages to the front end, and the messages are needed to be displayed in the lower right corner of the web page.
  2. Different operation buttons such as “Agree” and “Reject” are provided according to different message types.

2. Code Design.

  1. Using WebSocket to establish channels.
  2. The front end is based on umi+ antd + reconnecting websocket.js to development.
  3. Use express + express-ws + mockjs to create the WebSocket service channel and simulate the message pushed by the server.

3. Usage Method.

  1. The project needs to import the reconnecting-websocket.min.js, you can see its official documents for details.
  2. After successful login, call WebSocket to initialize.
    yield put({
        type: 'websocket/init',
        payload: {
            authToken
        }
    });

4. WebSocket Service Component Source Code.

  1. /service/websocket.js.
    /**
     * Import reconnecting-websocket library.
     * Encapsulate service file.
     */
    class Websocket{
     
      /**
       * websocket logic
       */
     
      constructor(){
        this.websocket=null;
        this.url='ws://127.0.0.1:30001/websocket-im';
        this.options={
          connectionTimeout: 5000,
          maxRetries: 10,
        };
      }
     
      init=()=>{
        this.websocket = new ReconnectingWebSocket(this.url,[], this.options);
      }
     
      close=()=>{
        this.websocket && this.websocket.close();
      }
     
      onMessage=(callback)=>{
        this.websocket && this.websocket.addEventListener('message', (e) => {
          callback&&callback(e)
        });
      }
     
    }
     
    const websocket = new Websocket();
     
    // Initialize connection.
    export function openWs() {
      return websocket.init();
    }
     
    // Close connection.
    export function closeWs() {
      return websocket.close();
    }
     
    // listen websocket message.
    export function onMessage() {
      let deferred;
      websocket.onMessage(function(e){
        if(deferred) {
            deferred.resolve(e)
            deferred = null 
        }
      });
      return {
        message() {
          if(!deferred) {
              deferred = {}
              deferred.promise = new Promise(resolve => deferred.resolve = resolve)
          }
          return deferred.promise;
        }
      }
    }
  2. /model/websocket.js.
     
    /**
     * Encapsulating model files
     * You should learn the components moment、immutable、antd、nanoid by yourself.
     */
    import {openWs,onMessage,closeWs} from 'services/websocket'
    import moment from 'moment'
    import { Map, fromJS } from 'immutable'
    import { notification } from 'antd'
    import nanoid from 'nanoid';
     
    const initState = Map({
     
      message:Map(), // received message.
      
    });
    export default {
      namespace: 'websocket',
     
      state: initState,
      subscriptions: {
        setup({ dispatch, history }) {
          dispatch({
            type: 'listener'
          });
          return history.listen(({ pathname, query }) => {
            
          });
        },
      },
      effects: {
     
        * listener({ payload }, { take, put, call }) {
          while (true) {
            const { type, payload } = yield take(['logout']);
            
            // Close the websocket if the message type is 'logout'.
            if (type === 'logout') {
              // Close websocket
              yield call(closeWs);
              notification.destroy();
              yield put({
                type: 'clearAllMessage', 
                payload:{
                }
              });
            }
          }
        },
     
        // Start websocket
        * init ({
          payload,
        }, { put, call, select }) {
          yield call(openWs);
          const listener = yield call(onMessage);
          yield put({type: 'receiveMsg', payload:{listener}});
        }, 
     
        // receive the message.
        * receiveMsg ({
            payload: {listener}
        }, { call, select, put}) {
            while(true){
              const event = yield call(listener.message);
     
              yield put({
                type: 'progressMsg', 
                payload:{
                  msg:JSON.parse(event.data)
                }
              });
              
                
            }
        },
     
        // process the message.
        * progressMsg ({
            payload: {msg}
        }, { call, select, put}) {
     
          console.log(msg)
          
          yield put({
            type: 'addOneMessage', 
            payload:{
              msg
            }
          });
            
        },
     
      },
      
      reducers: {
        
        addOneMessage(state, { payload:{msg} }) {
       
          const msgId = nanoid()+'-'+moment().format('x');
          return state.setIn(['message',msgId], fromJS({...msg,msgId}))
     
        },
     
        removeOneMessage(state, { payload:{msgId} }) {
       
          return state.deleteIn(['message',msgId])
     
        },
     
        clearAllMessage(state, { payload:{} }) {
       
          return state.setIn(['message'],Map())
     
        },
        
     
      },
      
    }

5. Notification Component Files Structure, Source Code.

  1. Notification component structure.
    Notyification
       - Demo1.js
       - Demo2.js
       - index.js
       - index.less
       - package.json
  2. Demo1.js.
    import React from 'react'
    import styles from './index.less'
     
    export default class NotificationSon extends React.Component {
      
      render(){
        const {note,intl:{formatMessage}} = this.props;
        let content=note.getIn(['content']);
     
        return(
            <div className={styles.Notification}>
              <div>{content}</div>
            </div>
        )
      }
      
    }
     
    NotificationSon.propTypes = {
      
    }
  3. Demo2.js.
    import React from 'react'
    import styles from './index.less'
    import { config } from 'utils'
    import { Button } from 'antd';
     
    const { defaultStyleSize } = config;
     
    export default class NotificationSon extends React.Component {
     
      dealApproval=(type,data)=>{
        const {dispatch,onClose} = this.props;
        if(type=='refuse'){
          console.log('Reject')
          onClose();
        }else if(type=='agree'){
          console.log('Agree')
          onClose();
        }
        
      }
      
      render(){
        const {note,intl:{formatMessage}} = this.props;
        let content=note.getIn(['content']);
     
        return(
            <div className={styles.Notification}>
              <div>{content}</div>
              <ul className={styles.btns}>
                <li>
                  <Button style={{ marginLeft: '12px' }} type={'primary'} size={defaultStyleSize}  onClick={() => {this.dealApproval('agree',note.get('data'))}}>{formatMessage({id: 'Global.agree'})}</Button>
                </li>
                <li>
                  <Button style={{ marginLeft: '12px' }} type={'danger'} size={defaultStyleSize}  onClick={() => {this.dealApproval('refuse',note.get('data'))}}>{formatMessage({id: 'Global.refuse'})}</Button>
                </li>
              </ul>
            </div>
        )
      }
      
    }
     
    NotificationSon.propTypes = {
      
    }
  4. index.js.
    /**
     * Source code of pop-up window in the lower right corner.
     */
    import React from 'react'
    import { injectIntl } from 'react-intl';
    import moment from 'moment'
    import { connect } from 'dva'
    import { notification } from 'antd';
    import Demo1 from './Demo1'
    import Demo2 from './Demo2'
     
    @injectIntl
    @connect(({
      websocket, 
    }) => ({ 
      websocket
    }))
    export default class Notification extends React.Component {
     
      componentWillReceiveProps(nextProps) {
        const {websocket,dispatch,intl, intl: { formatMessage }} = nextProps;
        let message=websocket.get('message');
     
        message.forEach((note)=>{
     
          let object=note.getIn(['object']);
          let msgId=note.getIn(['msgId']);
          let title=note.getIn(['title']);
          let content=note.getIn(['content']);
          let format = 'YYYY-MM-DD HH:mm:ss';
          let time=note.getIn(['ts'])?moment(note.getIn(['ts']), 'x').format(format):moment().format(format);
     
          switch (object) {
            case 'demo1':
              content=<Demo1
                            dispatch={dispatch}
                            intl={intl}
                            note={note}
                            onClose={()=>this.onClose(msgId)}
                        />;
                        break;
            case 'demo2':
              content=<Demo2
                dispatch={dispatch}
                intl={intl}
                note={note}
                onClose={()=>this.onClose(msgId)}
              />;
              break;
            default:
                        break;
                }
     
          notification.open({
            message: <span>{title} <small>{time}</small></span>,
            duration:30,
            key: msgId,
            description:content,
            placement: 'bottomRight',
            onClick: () => {
              
            },
            onClose: () => {
              this.onClose(msgId);
            }
          });
        })
     
      }
     
      // If message is closed.
      onClose=(msgId)=>{
        const {dispatch} = this.props;
        dispatch({
          type:'websocket/removeOneMessage',
          payload:{
            msgId
          }
        })
        return notification.close(msgId);
      }
      
      render(){
        return(
            null
        )
      }
      
    }
     
     
    Notification.propTypes = {
      
    }
  5. index.less.
    .Notification{
        .btns{
            padding: 0;
            margin: 15px 0 0 0;
            list-style: none;
            width: 100%;
            display: flex;
            justify-content: flex-end;
            li{
                margin-left: 10px;
            }
        }
    }
  6. package.json.
    {
      "name": "Notification",
      "version": "0.0.0",
      "private": true,
      "main": "./index.js"
    }
  7. Mockup message by express.js.
    let data = Mock.mock({
        
        "object|1":["demo1", "demo2"],
        "ts":new Date().getTime(),
        "title":"Message Title@string('number', 2)",
        "content":"You have a new message, @csentence(4, 10)",
        "data":{
            "audit_id":2,
            "host_ip":"9.9.9.9",
            "protocol":"ssh",
            "port":22,
            "conn_id":"3"
        }
    })
    
    ws.send(JSON.stringify(data))
    
    setTimeout(()=> {
    
         sendFunc()
    }, 3000)

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.