티스토리 뷰
코드 ver 0.2
import React, { useEffect, useState, useRef } from "react";
const SocketTest = () => {
const [socketConnected, setSocketConnected] = useState(false);
const [sendMsg, setSendMsg] = useState(false);
const [items, setItems] = useState([]);
const webSocketUrl = `ws://websocket.com`;
let ws = useRef(null);
// 소켓 객체 생성
useEffect(() => {
if (!ws.current) {
ws.current = new WebSocket(webSocketUrl);
ws.current.onopen = () => {
console.log("connected to " + webSocketUrl);
setSocketConnected(true);
};
ws.current.onclose = (error) => {
console.log("disconnect from " + webSocketUrl);
console.log(error);
};
ws.current.onerror = (error) => {
console.log("connection error " + webSocketUrl);
console.log(error);
};
ws.current.onmessage = (evt) => {
const data = JSON.parse(evt.data);
console.log(data);
setItems((prevItems) => [...prevItems, data]);
};
}
return () => {
console.log("clean up");
ws.current.close();
};
}, []);
// 소켓이 연결되었을 시에 send 메소드
useEffect(() => {
if (socketConnected) {
ws.current.send(
JSON.stringify({
message: sendMessage,
})
);
setSendMsg(true);
}
}, [socketConnected]);
return (
<div>
<div>socket</div>
<div>socket connected : {`${socketConnected}`}</div>
<div>res : </div>
<div>
{items.map((item) => {
return <div>{JSON.stringify(item)}</div>;
})}
</div>
</div>
);
};
export default SocketTest;
onmessage 메서드는 send 후 데이터가 올 때 트리거가 되므로 웹소켓 객체 정의 안으로 이동했습니다. send 메소드는 따로 빼지 않고 onopen 함수 안에 넣어도 됩니다.
코드 ver 0.1
import React, { useEffect, useState, useRef } from "react";
const SocketTest = () => {
const [socketConnected, setSocketConnected] = useState(false);
const [sendMsg, setSendMsg] = useState(false);
const [items, setItems] = useState([]);
const webSocketUrl = `ws://websocket.com`;
let ws = useRef(null);
// 소켓 객체 생성
useEffect(() => {
if (!ws.current) {
ws.current = new WebSocket(webSocketUrl);
ws.current.onopen = () => {
console.log("connected to " + webSocketUrl);
setSocketConnected(true);
};
ws.current.onclose = (error) => {
console.log("disconnect from " + webSocketUrl);
console.log(error);
};
ws.current.onerror = (error) => {
console.log("connection error " + webSocketUrl);
console.log(error);
};
}
return () => {
console.log("clean up");
ws.current.close();
};
}, []);
// 소켓이 연결되었을 시에 send 메소드
useEffect(() => {
if (socketConnected) {
ws.current.send(
JSON.stringify({
message: sendMessage,
})
);
setSendMsg(true);
}
}, [socketConnected]);
// send 후에 onmessage로 데이터 가져오기
useEffect(() => {
if (sendMsg) {
ws.current.onmessage = (evt) => {
const data = JSON.parse(evt.data);
console.log(data);
setItems((prevItems) => [...prevItems, data]);
};
}
}, [sendMsg]);
return (
<div>
<div>socket</div>
<div>socket connected : {`${socketConnected}`}</div>
<div>res : </div>
<div>
{items.map((item) => {
return <div>{JSON.stringify(item)}</div>;
})}
</div>
</div>
);
};
export default SocketTest;
코드를 짜면서 고민했던 점은 컴포넌트가 unmount 되었을 때 socket 연결이 끊어지기를 바랬습니다. 여러 시행 착오 끝에 소켓 객체를 생성하는 useEffect에 clean up을 하는 것이 원하는대로 동작하였습니다.
소켓 객체를 컴포넌트 밖에 전역으로 생성하기 보다는 컴포넌트에 ref를 통해 저장이 되도록 하고, 소켓 객체의 send 메소드와 onmessage 메소드가 순차적으로 실행되기를 바래서 위와 같이 작성했습니다.
반응형
'React' 카테고리의 다른 글
react 컴포넌트가 unmount 된 후 setState가 실행되는 문제 해결 방법 (0) | 2021.07.12 |
---|---|
폴더 안의 파일을 모두 import 하는 방법 (0) | 2021.02.16 |
redux 강의 기본 핵심 튜토리얼 5탄 - redux data 사용하기 (0) | 2020.11.16 |
redux 강의 기본 핵심 튜토리얼 4탄 - redux data flow (0) | 2020.11.11 |
redux 강의 기본 핵심 튜토리얼 3탄 - redux app 구조 (0) | 2020.11.03 |
댓글
공지사항