source

리액트 훅 + WebSockets의 올바른 사용 방법

manycodes 2023. 3. 27. 21:22
반응형

리액트 훅 + WebSockets의 올바른 사용 방법

WebSockets 서버에 연결하여 메시지를 기록해야 합니다.React 클래스 컴포넌트를 사용하여 이 논리를 삽입합니다.componentDidMount라이프 사이클 훅을 사용하여 즐겁게 이행할 수 있지만, 어떻게 훅을 사용하여 적절히 구현해야 할지 잘 모르겠습니다.

제 첫 번째 시도는 이렇습니다.

import React, {useEffect} from 'react';

export default function AppWs() {
  useEffect(() => {
    let ws = new WebSocket('wss://ws.kraken.com/');
    ws.onopen = () => console.log('ws opened');
    ws.onclose = () => console.log('ws closed');

    ws.onmessage = e => {
      const message = JSON.parse(e.data);
      console.log('e', message);
    };

    return () => {
      ws.close();
    }
  }, []);

  return (
    <div>hooks + ws</div>
  )
}

에 접속 및 로그 로직을 추가했습니다.useEffect의존관계가 있는 빈 어레이가 제공되어 모든 것이 정상적으로 동작했습니다.추가가 필요할 때까지pause로깅을 일시 정지합니다.

export default function AppWs() {
  const [isPaused, setPause] = useState(false);

  useEffect(() => {
    let ws = new WebSocket('wss://ws.kraken.com/');
    ws.onopen = () => console.log('ws opened');
    ws.onclose = () => console.log('ws closed');

    ws.onmessage = e => {
      if (isPaused) return;
      const message = JSON.parse(e.data);
      console.log('e', message);
    };

    return () => {
      ws.close();
    }
  }, []);

  return (
    <div>
      <button onClick={() => setPause(!isPaused)}>{isPaused ? 'Resume' : 'Pause'}</button>
    </div>
  )
}

ESLint가 나한테 소리를 지르기 시작했는데isPaused의존 관계로서 진술하다useEffect.
음, 그래, 됐어.
그러나 버튼을 클릭할 때마다 WS 서버에 재접속되어 있는 것을 알 수 있었습니다.이건 분명히 내가 원하는게 아니야.

내 다음 반복은 두 개를 사용하는 것이었다.useEffects: 1개는 접속용, 1개는 메시지 처리용.

export default function AppWs() {
  const [isPaused, setPause] = useState(false);
  const [ws, setWs] = useState(null);

  useEffect(() => {
    const wsClient = new WebSocket('wss://ws.kraken.com/');
    wsClient.onopen = () => {
      console.log('ws opened');
      setWs(wsClient);
    };
    wsClient.onclose = () => console.log('ws closed');

    return () => {
      wsClient.close();
    }
  }, []);

  useEffect(() => {
    if (!ws) return;

    ws.onmessage = e => {
      if (isPaused) return;
      const message = JSON.parse(e.data);
      console.log('e', message);
    };
  }, [isPaused, ws]);

  return (
    <div>
      <button onClick={() => setPause(!isPaused)}>{isPaused ? 'Resume' : 'Pause'}</button>
    </div>
  )
}

이것은 예상대로 동작합니다만, 뭔가 놓치고 있는 것 같은 느낌이 들고, 이 태스크는 1개로 간단하게 해결할 수 있습니다.useEffect리액트 훅을 올바르게 사용하고 있는지 확인할 수 있도록 코드를 리팩터링 해 주세요.감사합니다!

웹 소켓을 한 번만 설정하기 때문에 상태가 아닌 ref를 사용하는 것이 더 좋다고 생각합니다.

순서useEffect중요합니다.

George가 댓글로 제시한 것처럼 첫 번째,useEffect ws.current변수에 저장되기 때문에close같은 인스턴스를 가리킵니다.

export default function AppWs() {
    const [isPaused, setPause] = useState(false);
    const ws = useRef(null);

    useEffect(() => {
        ws.current = new WebSocket("wss://ws.kraken.com/");
        ws.current.onopen = () => console.log("ws opened");
        ws.current.onclose = () => console.log("ws closed");

        const wsCurrent = ws.current;

        return () => {
            wsCurrent.close();
        };
    }, []);

    useEffect(() => {
        if (!ws.current) return;

        ws.current.onmessage = e => {
            if (isPaused) return;
            const message = JSON.parse(e.data);
            console.log("e", message);
        };
    }, [isPaused]);

    return (
        <div>
            <button onClick={() => setPause(!isPaused)}>
                {isPaused ? "Resume" : "Pause"}
            </button>
        </div>
    );
}
 useEffect(() => {
const socket = new WebSocket('wss://ws.kraken.com');
socket.addEventListener('message', function (event) {
  const a = JSON.parse(event.data);
  setPriceWebSocket(a);

  const amin = socket.send(
    JSON.stringify({
      event: 'subscribe',
      pair: ['XBT/USD', 'XBT/EUR', 'ADA/USD'],
      subscription: { name: 'ticker' },
    }),
  );
  

});

언급URL : https://stackoverflow.com/questions/60152922/proper-way-of-using-react-hooks-websockets

반응형