![](/img/trans.png)
[英]Unable to establish connection between Node.JS and React-Native (Socket.IO)
[英]Unable to properly establish a connection between React Native client and Node.js server with redux-saga and socket.io
快速上下文:我正在嘗試構建評論頁面的反應原生原型,用戶可以在其中接收實時更新(評論、用戶進入評論屏幕、用戶離開等)。 為此,我使用 react-redux、redux-saga、socket.io 和 node.js(服務器)。 我是 redux-saga 的新手,所以我可能在這里遺漏了一些明顯的東西,所以請稍等……罪魁禍首肯定在於watchCommentActions函數/傳奇……
問題:一旦安裝完成,評論屏幕就會發送以下操作 { type:comment.room.join, value },然后 rootSaga 會正確地確認它,但是,當嘗試使用 promise 連接到套接字時- 通過const socket = yield call(connect) 解析結構; promise 永遠不會解決,這會阻塞生成器(它不會進入下一個產量)。 奇怪的是,另一方面,服務器確實記錄了與套接字的連接,所以連接客戶端 --> 服務器似乎沒問題。 此外,通過熱重新加載應用程序,我可以設法解決 promise (就像生成器需要運行兩次才能解決套接字連接),但是socket.emit("join-room")永遠不會到達服務器和生成器再次卡住。 同樣,當我嘗試通過發布評論來觸發寫入生成器並因此調度 {type:comment.post.start, value } 時 *socket.emit("comment", {text: value.text}) 不會到達服務器。 簡而言之,沒有什么真正起作用,也沒有拋出任何錯誤......太好了。
最后的話:在將我的套接字邏輯移動到 saga 之前,套接字連接是無縫工作的。 I've also tried to reuse the documentation's implementation with channels by using the same connect function instead of createWebSocketConection ( https://redux-saga.js.org/docs/advanced/Channels.html ) but the promise-resolve-socket situation仍然發生。 另外,我注意到類似的問題來自我研究過的同一個 git 存儲庫以了解 sagas 邏輯( https://github.com/kuy/redux-saga-chat-example/blob/master/src/client/ sagas.js ),但是,它們都沒有讓我理解我的實現有什么問題。 最后,如果有更好的方法用 redux-saga 實現這個邏輯,我很感興趣,我想要的只是一個健壯的、集中的、可重用的實現。
薩加斯/index.js
import { all, takeEvery, takeLatest } from "redux-saga/effects";
import { comment } from "../Reducers/commentCacheReducer";
import { like } from "../Reducers/postsCacheReducer";
import { posts } from "../Reducers/postsReducer";
import flow from "./commentSagas";
import { likePost, unlikePosts } from "./likeSagas";
import { fetchPosts } from "./postsSagas";
function* watchLikeActions() {
yield takeLatest(like.add.start, likePost);
yield takeLatest(like.remove.start, unlikePost);
}
function* watchFetchActions() {
yield takeEvery(posts.fetch.start, fetchPosts);
}
function* watchCommentsActions() {
yield takeEvery(comment.room.join, flow);
}
export default function* rootSaga() {
yield all([watchLikeActions(), watchFetchActions(), watchCommentsActions()]);
}
Sagas/commentSaga.js
import { eventChannel } from "redux-saga";
import { call, cancel, fork, put, take } from "redux-saga/effects";
import io from "socket.io-client";
import { endpoint } from "../../API/ServerAPI";
import { addUser, fetchComment, leaveRoom, removeUser } from "../Actions/commentActions";
import { comment } from "../Reducers/commentCacheReducer";
function connect() {
const socket = io(endpoint);
return new Promise((resolve) => {
socket.on("connection", () => {
resolve(socket);
});
});
}
function subscribe(socket) {
return new eventChannel((emit) => {
socket.on("users.join-room", ({ userId }) => {
emit(addUser({ userId }));
});
socket.on("users.leave-room", ({ userId }) => {
emit(removeUser({ userId }));
});
socket.on("comments.new", ({ comments }) => {
emit(fetchComment({ comments }));
});
socket.on("users.join-room", ({ userId }) => {
emit(addUser({ userId }));
});
return () => {};
});
}
function* read(socket) {
const channel = yield call(subscribe, socket);
while (true) {
let action = yield take(channel);
yield put(action);
}
}
function* write(socket) {
while (true) {
const { value } = yield take(comment.post.start);
socket.emit("comment", { text: value.text });
}
}
function* handleIO(socket) {
yield fork(read, socket);
yield fork(write, socket);
}
export default function* flow() {
const socket = yield call(connect);
socket.emit("join-room", (res) => {
console.log(JSON.stringify(res));
});
const task = yield fork(handleIO, socket);
let action = yield take(leaveRoom);
yield cancel(task);
yield put(action);
socket.emit("leave-room");
}
服務器.js
const http = require("http");
const app = require("./app");
const socketIo = require("socket.io");
const mongoose = require("mongoose");
const normalizePort = (val) => {
const port = parseInt(val, 10);
if (isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
};
const port = normalizePort(process.env.PORT || "3000");
app.set("port", port);
const errorHandler = (error) => {
if (error.syscall !== "listen") {
throw error;
}
const address = server.address();
const bind = typeof address === "string" ? "pipe " + address : "port: " + port;
switch (error.code) {
case "EACCES":
console.error(bind + " requires elevated privileges.");
process.exit(1);
break;
case "EADDRINUSE":
console.error(bind + " is already in use.");
process.exit(1);
break;
default:
throw error;
}
};
const server = http.createServer(app);
const io = socketIo(server);
server.on("error", errorHandler);
server.on("listening", () => {
const address = server.address();
const bind = typeof address === "string" ? "pipe " + address : "port " + port;
console.log("Listening on " + bind);
});
// comments room
// Storing in variable just for testing purposes, will
// connect to MongoDB once the socket problem gets solved.
let userIds = [];
io.on("connection", (socket) => {
console.log("[server] connect");
});
io.on("join-room", (socket, {userId}) => {
console.log(`[server] join-room: ${userId}`);
userIds.push(userId);
socket.socket.username = userId;
socket.broadcast.emit("users.join-room", { userId });
});
io.on("leave-room", (socket) => {
const { userId } = socket.socket;
if (userId) {
console.log(`[server] leaving-room: ${userId}`);
userIds = userIds.filter((u) => u !== userId);
delete socket.socket["userId"];
socket.broadcast("users.leave-room", { userId });
}
});
// Storing in variable just for testing purposes, will
// connect to MongoDB once the socket problem gets solved.
let messages = [];
io.on("comment", (socket, { text }) => {
console.log(`[server] message: ${text}`);
const message = {
id: messages.length,
text,
userId: socket.socket.userId
};
messages.push(message);
socket.broadcast("comments.new", { message });
});
編輯 1在快速瀏覽 socket.io 文檔后,我意識到我的服務器快速實現有問題,我只是忘記在連接協議中注冊事件處理程序......但是,仍然需要觸發生成器兩次才能啟動套接字連接,允許promise解決和用戶加入插座房。
io.on("connect", (socket) => {
console.log("[server] connect");
socket.on("join-room", ({ userId }) => {
console.log(`[server] join-room: ${userId}`);
userIds.push(userId);
socket.username = userId;
socket.broadcast.emit("users.join-room", { userId });
});
socket.on("leave-room", ({ userId }) => {
if (userId) {
console.log(`[server] leaving-room: ${userId}`);
userIds = userIds.filter((u) => u !== userId);
delete socket["userId"];
socket.broadcast.emit("users.leave-room", { userId });
}
});
socket.on("comment", ({ text }) => {
console.log(`[server] message: ${text}`);
const message = {
id: messages.length,
text,
userId: socket.userId
};
messages.push(message);
socket.broadcast.emit("comments.new", { message });
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.