МОЯ ПРОБЛЕМА
У меня есть сервер, который получает потоковые данные через UDP и ретранслирует данные через веб-сокеты. В моем интерфейсе у меня есть 2 разных компонента, которые собирают данные и отображают значения. Всякий раз, когда мой сервер транслирует объект, ключ A подбирается компонентом 1. А ключ B должен подхватываться компонентом B. В целях отладки приведенный ниже код работает гладко, если бы я использовал один компонент, но как только я использую оба компонента, только один из них может правильно получать и обновлять данные, а другой ничего не делает. Что я делаю не так?
МОЙ СЕРВЕР (Только важные вещи)
# Dict to hold values
var data = {"score" : 0, "session" : 0,}
# handle different incoming UDP packets
client.on(PACKETS.session, handle_session);
client.on(PACKETS.score, handle_score);
#update data.session object with new values
function handle_session(data) {
data['session'] = data.session
websocket.broadcast(data);
}
#update data.score object with new values
function handle_score(data) {
data['score'] = data.score
websocket.broadcast(data);
}
# Broadcast data function gets called in handle functions.
websocket.broadcast = function broadcast(data) {
websocket.clients.forEach(function each(client) {
console.info(data);
client.send(data);
});
};
МОЕ РЕАКТИВНОЕ ПРИЛОЖЕНИЕ
CONTEXT.JS — создать сокет
export const socket = new WebSocket("ws://localhost:8000")
export const SocketContext = React.createContext();
APP.JS - я оборачиваю оба своих компонента в SocketContext
function App() {
return (
<div className = "App">
<SocketContext.Provider value = {socket}>
< Score />
< Session />
</SocketContext.Provider>
</div>
SCORE.JS — Компонент №1 загружает сокет из контекста.
function Score() {
const [score, setScore] = useState(0)
const websocket = useContext(SocketContext);
useEffect(() => {
websocket.onmessage = function(e) {
var packet = JSON.parse(e.data);
setScore(packet.score)
}
}, [websocket,]);
return (
<h6>{score}</>
);
}
export default Score;
SESSION.JS — компонент номер 2 загружает тот же сокет из контекста.
function Session() {
const [session, setSession] = useState(0)
const websocket = useContext(SocketContext);
useEffect(() => {
websocket.onmessage = function(e) {
var packet = JSON.parse(e.data);
setSession(packet.session)
}
}, [websocket,]);
return (
<h6>{session}</>
);
}
export default Session;
Таким образом, при запуске внешнего интерфейса и добавлении ведения журнала консоли в useEffect для обоих компонентов одновременно запускается только один. Потом при перезагрузке приложения. Еще один бежит. Они никогда не работают одновременно.
У вас есть какие-то конкретные сообщения об ошибках в консоли?
Этот бит на стороне сервера кажется проблематичным:
data['score'] = {data.score}
Вроде должно быть:
data['score'] = data.score;
Редактировать*
Также я вижу еще одну проблему: перезапись переменной области:
Ты устанавливаешь:
var data = {"score" : 0, "session" : 0,}
Но позже обе ваши функции используют data
в своей локальной области видимости, что не очень хорошо и может вызвать проблемы:
function handle_session(data) {
Вероятно, должно быть:
function handle_session(d) {
Также это:
websocket.broadcast = function broadcast(data) {
Вероятно, должно быть:
websocket.broadcast = function broadcast(d) {
Эти функции могут использовать одну и ту же переменную внутренней области видимости, потому что они являются родственными.
*** РЕДАКТИРОВАТЬ, ОБНОВЛЕННЫЙ ОТВЕТ
Проблема заключается в использовании d
. Поскольку websocket.onmessage
— это один экземпляр, совместно используемый компонентами, после того как прослушиватель установлен для свойства websocket
внутри App.js, последующие дочерние компоненты будут игнорироваться, когда они попытаются установить один и тот же прослушиватель для того же свойства в том же экземпляре веб-сокета.
Ключ в том, чтобы использовать onmessage
вместо этого!
https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/message_event
Я создал простой рабочий пример приложения React <> Express <> Websocket для вашей ситуации, решенной с помощью addListener
. Я воспроизвел вашу точную проблему.
Теперь все 3 компонента useEffects будут правильно прослушиваться, как вы и ожидали.
Откройте терминал и запустите: npm run dev https://codesandbox.io/p/sandbox/bitter-mountain-q3x118
Надеюсь, это поможет!
Привет, Джеки. Звучит хорошо. Нашел проблему и обновил свой ответ: ключ в том, чтобы заменить использование «websocket.onmessage» на websocket addEventListener, который создает новый прослушиватель вместо того, чтобы пытаться переписать тот же прослушиватель в том же общем экземпляре веб-сокета. См.: WebSocket AddListener Рабочая песочница
Отличный! Это прекрасно работает. Я потратил 2 дня на эту проблему и даже близко не решил ее. Большое спасибо, сэр.
Спасибо за ответ, Уэсли. Я переписал голую часть кода сервера только для презентационных целей, это всего лишь опечатки (извините, исправлю немедленно). При входе в консоль в моем приложении React я вижу всю информацию, полученную моими приложениями. Суть моей проблемы в том. Похоже, что мой веб-объект может использоваться только одним компонентом за раз. Он не передается через SocketContext.