Z góry dziękuję za wszelkie sugestie. Wdrażam tu Websocket w ReactJS i moim celem jest zapełnienie mojego stanu historii nadchodzącymi zdarzeniami „onmessage”. Co dziwne dla mnie, setHistory opróżnia moją tablicę po odebraniu wiadomości ze zdarzeń „websocket.onmessage”. Usuwa nawet mój stan początkowy. Uproszczona wersja poniżej:
function NotificationWebSocket ({object_id}) {
const [history, setHistory] = useState([{text: "The first notification"}]) //
function connectToWebSocket() {
const wsStart = (window.location.protocol === "https:" ? "wss://" : "ws://")
const url = 'localhost:8000/live/'
let socket = new ReconnectingWebSocket(wsStart + url + object_id)
socket.onmessage = e => {
console.log(e.data) // logs the received data correctly
setHistory([...history, {text: e.data}]) // ?? this is setting my history state array to null... ??
setHistory(history.append({text: e.data})) //also cleans my history array here.
}
}
useEffect(() => {
connectToWebSocket()
},[]) // so that we only connect to the websocket once
return (
<div>
We are on a live connection to the server.
{history.map(item=> <div>{item.text}</div>)}
</div>
)
}
Rzeczy do zapamiętania: używam biblioteki ReconnectingWebSocket, chociaż próbowałem jej nie używać i dzieje się to samo. Moje connectToWebSocket jest wyzwalane z wnętrza metody useEffect, w przeciwnym razie otrzymuję kilka żądań Websocket na serwerze.
Jeszcze raz dziękuję, Felipe.
2 odpowiedzi
Masz przestarzałe zamknięcie, jest to częsty błąd, który jest często popełniany podczas używania punktów zaczepienia z zależnościami (takich jak useEffect
, useMemo
, useCallback
). Zajrzyj tutaj.
Rozwiązaniem jest zawsze uwzględnianie wszystkich zmiennych, których będziesz używać w wywołaniu zwrotnym useEffect
na liście zależności . W twoim przypadku trudno je dostrzec, ponieważ większość z nich jest ukryta wewnątrz funkcji connectToWebSocket
, która jest aktualizowana przy każdym renderowaniu, z wyjątkiem ... tego wywoływanego przez useEffect
jest tym, który został utworzony na pierwszy render, a wywołanie zwrotne onmessage
zamyka stan, który komponent miał przy pierwszym renderowaniu.
Ponieważ używasz WebSocket, nie wystarczy po prostu useEffect
za każdym razem, gdy history
się zmienia, ponieważ wtedy będziesz mieć wiele połączeń (jedno na każdą zmianę), musisz też rozłączyć się przy następnej wywoływany jest efekt i możesz to zrobić, zwracając funkcję z wywołania zwrotnego useEffect
, która rozłącza się z WebSocket, tak aby efekt mógł się ponownie połączyć. Jest to również przykład, który jest koncepcyjnie wyjaśniony w dokumentach Reacta, kiedy pokazuje przykład o useEffect.
Często sugeruje się, aby uniknąć tego rodzaju sytuacji
- Zdefiniuj funkcję, którą zamierzasz wywołać w wywołaniu zwrotnym
useEffect
w samym wywołaniu zwrotnym, zamiast poza nim; - Użyj swojego ulubionego lintera, aby ostrzec Cię o brakujących zależnościach w Twoich
useEffect
(lub podobnych) połączeniach. Jeśli spróbujeszcreate-react-app
, to jest już skonfigurowane.
Ponadto, jak sugeruje @ ako-javakhishvili, za każdym razem, gdy twój następny stan zależy od poprzedniej wartości samego stanu, wywołaj funkcję ustawiającą z wywołaniem zwrotnym zamiast wartości bezpośredniej. To rozwiąże Twój problem w tym przypadku, ale nadal będziesz mieć nieaktualne zamknięcie i również powinieneś się tym zająć.
Możesz po prostu zmienić setHistory([...history, {text: e.data}])
za pomocą następującego kodu setHistory(history=> [...history, {text: e.data}])
Podobne pytania
Nowe pytania
reactjs
React to biblioteka JavaScript do tworzenia interfejsów użytkownika. Wykorzystuje deklaratywny paradygmat oparty na komponentach i ma być zarówno wydajny, jak i elastyczny.