我們在 App 中如果 App 是在背景狀態,可以使用手機原生的 notification 進行即時通知,但是如果App目前是打開的狀態,想要及時通知,就需要使用 websocket

在前台RN專案訂閱後端的 socket 服務,必須要跟後端配合,才能順利接收到資料,下一篇文章會分享如何使用 express + socket.io 發送訊息。

package版本 :

  • React Native 0.63.3
  • socket.io-client 2.3.1

大綱 :

  1. 安裝 Socket.io
  2. connect socket
  3. subscribe

安裝 Socket.io

$ yarn add socket.io-client

 


connect socket

要先確定後端開給你的 socket 網址,因為通常不會跟 restful api 放在同一個接口。

如果是登入狀態下要訂閱,通常後端會需要你提供使用者token,所以連線時要一併傳到後端。

因為我想要使用者在進去首頁後才開始接收訊息,避開登入那些頁面,所以整個socket程式碼的部分就寫在Home.js,沒有放在App.js

我會在最下面放整頁程式碼,這邊先一步一步說明紀錄一下。

 

引入套件 :

import io from 'socket.io-client';

 

宣告變數放你的 socket 實例 :

import React, {
  useEffect,
  useState
} from 'react';

const Home = () => {
    const [ws, setWs] = useState(null);
}

 

創建 socket 實例的寫法 :

io(API_HOST, { path: '/ws', query: { token: auth.userToken } })

API_HOST是我放在.env環境變數的api網址,就看後端給你的網址是啥。

path就是後面的 endpoint,這邊都是看後端給你的網址去決定。

token或其他資料可以用query參數帶給後端。

所以你可以把它整個放進剛剛宣告的state中。

useEffect(() => {
  setWs(io(API_HOST, { path: '/ws', query: { token: auth.userToken } }));
}, [ws]);

 

連線到socket server寫法 :

ws.on('connect', () => {
  console.log('client connect success');
});
ws.on('error', error => {
  console.log(error);
});

ws就是剛剛宣告的state


subscribe

連線成功後要在他的 callback function 內去訂閱頻道,這就要看你跟後端協議的頻道名稱,前後端有對上才收得到,也就是說一個網站可以有各種不同頻道。

訂閱頻道寫法 :

ws.on('getOrder', function (msg) {
  console.log(msg);
});

 

只是這個寫法要放在 on connect 的 callback 中。

like this :

ws.on('connect', () => {
  console.log('client connect success');
  ws.on('getOrder', function (msg) {
    console.log(msg);
  });
});

getOrder就是我的頻道名稱,後端也必須針對getOrder發送訊息,才可以收到。

 

所以這邊我們可以把整個連線初始化的流程寫成一個 function。

const initConnectSocket = () => {
  ws.on('connect', () => {
    console.log('client connect success');
    ws.on('getOrder', function (msg) {
      console.log(msg);
      if (msg && msg.hasOrder) {
        Alert({ title: '有新訂單!', onOk: getClientRequest });
      }
    });
  });
  ws.on('error', error => {
    console.log(error);
  });
};

然後在剛剛初始化的useEffect做防呆的判斷 :

useEffect(() => {
  ws
    ? initConnectSocket()
    : setWs(io(API_HOST, { path: '/ws', query: { token: auth.userToken } }));
  return () => {
    ws && ws.close();
  };
}, [ws]);

記住要在useEffect return的時候取消訂閱 socket


完整代碼如下 :

import React, {
  useEffect,
  useState
} from 'react';
import io from 'socket.io-client';

const Home = () => {
  const [ws, setWs] = useState(null);

  useEffect(() => {
    ws
      ? initConnectSocket()
      : setWs(io(API_HOST, { path: '/ws', query: { token: auth.userToken } }));
    return () => {
      ws && ws.close();
    };
  }, [ws]);

  const initConnectSocket = () => {
    ws.on('connect', () => {
      console.log('client connect success');
      ws.on('getOrder', function (msg) {
        console.log(msg);
        if (msg && msg.hasOrder) {
          Alert({ title: '有新訂單!', onOk: getClientRequest });
        }
      });
    });
    ws.on('error', error => {
      console.log(error);
    });
  };
}
export default Home;
0
0 回復

發表評論

想要加入討論嗎?
請盡情發表您的想法!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。