2016-04-15 7 views
8

Nie jestem pewien, czy problem polega na tym, w jaki sposób mam skonfigurowane gniazda - czy też niepoprawnie próbuję renderować dane z React.React and Socket.io: Potrafi uzyskać wstępne dane - ale widok nie jest aktualizowany po pojawieniu się nowego posta.

Mogę pomyślnie pobierać dane z mojego gniazda - ale nie aktualizuje się, gdy nowe dane są wysyłane na serwer. Moja intencja dotyczy stanu w React, aby automatycznie renderować nowe dane, które są zawsze aktywne z powodu połączenia przez gniazdo.

Oto moja aplikacja klient, który pobiera wiadomości z serwera i czyni je:

var Chat = React.createClass({ 
    getInitialState: function() { 
    return { 
     messages: null 
    } 
    }, 
    componentWillMount: function(){ 
    var self = this; 
    socket.emit('getMessages'); 
    socket.on('serverMessages', function (data) { 
     self.setState({messages: data}) 
    }); 
    }, 
    render: function() { 
    var messages = this.state.messages ? <MessageList messages={this.state.messages}/> : null 
    return (
     <div className="jumbotron"> 
     { messages } 
     <MessageForm submitMessage={this.submitMessage}/> 
     </div> 
    ); 
    } 
}); 

Tylko w przypadku, tutaj jest mój kod serwera, który emituje dane:

io.on('connection', function (socket) { 

    socket.on('getMessages', function (data) { 
    Message.find(function(err, messages){ 
     socket.emit('serverMessages', messages); 
    }) 
    }); 

}); 

Odpowiedz

3

Kod serwer jest tylko wypalanie na początkowym gnieździe connection.

Serwer:

socket.on('getMessages', function (data) { 
    Message.find(function(err, messages){ 
    socket.emit('serverMessages', messages); 
    }) 
}); 

Klient:

var Chat = React.createClass({ 
    getInitialState: function() { 
    return { 
     messages: null 
    } 
    }, 
    componentWillMount: function(){ 
    var self = this; 
    socket.emit('getMessages'); 
    socket.on('serverMessages', function (data) { 
     self.setState({messages: data}) 
    }); 
    }, 
    render: function() { 
    var messages = this.state.messages ? <MessageList messages={this.state.messages}/> : null 
    return (
     <div className="jumbotron"> 
     { messages } 
     </div> 
    ); 
    } 
}); 

oparciu o nazewnictwo, wydaje się również, że Message.find() ciągnie pojedynczej wiadomości. Poleciłbym wyjaśnić etykietowanie, aby dopasować liczność.

+0

Kod został napisany pośpiesznie w przeglądarce i nie został przetestowany, dlatego przepraszam, jeśli występują błędy literowe/logiczne. Kluczową wadą w oryginalnym przykładzie była brakująca obsługa zdarzeń dla 'getMessages' – kwcto

+0

Dzięki @kwcto - Zaimplementowałem twoją opinię, ale nadal zachowuje się tak samo. Nowe wiadomości pojawiają się tylko po odświeżeniu strony. (Zaktualizowałem pytanie, aby odzwierciedlić nową implementację) – fresh5447

4

Spróbuj tego:

var Chat = React.createClass({ 
    getInitialState: function() { 
    return { 
     messages: null 
    } 
    }, 
    componentWillMount: function(){ 
    var self = this; 
    socket.emit('getMessages'); 
    socket.on('serverMessages', function (data) { 
     self.setState({messages: data}) 
    }); 
    }, 
    render: function() { 
    var messages = this.state.messages ? <MessageList messages={this.state.messages}/> : null 
    return (
     <div className="jumbotron"> 
     { messages } 
     <MessageForm submitMessage={this.submitMessage}/> 
     </div> 
    ); 
    } 
}); 
4

od teraz, jesteś „tylko” zgrywania danych z serwera, gdy komponent został załadowany. Aby uzyskać coś bardziej "w czasie rzeczywistym", możesz albo wysłać polecenie ping do tego samego, podanego przez Ciebie, regularnego oświadczenia emit (co nie pozwala na korzystanie z websockets, naprawdę można używać długiego pobierania) lub regularnie mieć serwer wyślij nowe dane do wszystkich klientów.

Można to zrobić albo:

A) po stronie klienta: "Polling" dla informacji [nie jest idealny]

Uwaga: I początkowo umieścić to w mojej odpowiedzi, bo widziałem OP było "odpytywanie" po załadowaniu kontrolera. Nie kliknąłem, że może to być spowodowane tym, że kontroler może nie być załadowany za pomocą websocket, więc wysyłanie danych na połączenie może nie działać tutaj. Mój błąd.

Wymień socket.emit('getMessages') z czymś, co będzie "poll" THE websocket regularnie dla danych:

setInterval(function() { 
    socket.emit('getMessages') 
}, 10000); /* Request data from the socket every 10 seconds */ 

LUB

B) po stronie serwera: Wyślij nowe dane, jak tylko będą dostępne. [Najlepsza metoda]

Śledź wszystkich klientów za pomocą tablicy klientów i usuń z niej po zakończeniu sesji.

var clients = []; 

io.on('connection', function (socket) { 
    clients.push(socket); 

    socket.on('end', function() { 
     // Could also splice the array below, but it still works. 
     delete clients[clients.indexOf(socket)]; 
    }); 


    /* Previous logic for server goes here */ 
}); 

uruchomić ten kod, kiedy trzeba wcisnąć nowe wiadomości ze składowania bazy danych/data:

for (var i in clients) { 
    clients[i].emit('serverMessages', /* messages object */); 
} 
+0

Odnośnie opcji A: To nie brzmi dobrze, gdy trzeba sondować na kliencie. Czy gniazdo klienta podłączone do gniazda serwera nie tworzy strumienia danych na żywo ? – fresh5447

+0

Opcja B jest najlepszym sposobem - myślałem, że wspomniałem o tym, ale oczywiście nie. Wydałem, że początkowo odpytujesz, ale w ten sposób ma to sens w przypadku, gdy Twój komponent nie zostanie załadowany po podłączeniu do websocket lub tak: P –

+0

Używanie rozgłaszania/emitowania oraz w przestrzeniach nazw lub pokojach może być bezpieczniejsze (i łatwiejsze) niż zachowanie śledzenie klientów (tablica 'clients'). Po uruchomieniu wielu instancji węzła, tablica 'clients' będzie zawierała tylko instancje połączone z tym konkretnym hostem. To samo jest prawdą domyślnie z socket.io, ale oficjalnie zalecane są sposoby postępowania z wieloma hostami https://socket.io/docs/using-multiple-nodes/ – tybro0103

1

Czy to możliwe ze względu na jego metody componentWillMount cyklem życia? Czy mógłbyś zamiast tego wypróbować componentDidMount?

Wygląda na to, że render wyświetli aktualizację stanu, ale zostanie wykonany tylko jeden raz, pomimo zmiany stanu zgodnie z facebook.

Powiązane problemy