섹션 2. 서버 API 연동하기
8강. 웹소켓 연결하기
1) 웹소켓 기반 라이브러리
요청-응답 방식이 아니라 실시간 양방향 통신 가능
기존 : app → axios → 응답
소켓 : 한 번만 연결을 맺으면 연결이 끊어지기 전까지 실시간으로 가능. 서버에서 먼저 보내줄 수도 있다.
대신, 배터리 소모가 있다.
npm i socket.io-client
웹소켓 라이브러리 설치
2) Custom hooks
자주 쓰는 것은 hook으로 만든다.
Custom hook에 익숙해져야 한다.
import { io, Socket } from 'socket.io-client';
import Config from 'react-native-config';
let socket: Socket | undefined;
const useSocket = () => {
socket = io(`${Config.API_URL}, {
transports: ['websocket'],
});
};
export default useSocket;
이게 기본 포맷
소켓 통신이 안될 때 실시간으로 통신이 되는 것처럼 빠르게 요청 → 응답하는 것을 long-polling이라고 한다. 그런데 이 방식은 서버에 무리를 줄 수 있기 때문에 가급적 쓰지 않는 것이 좋다.
즉, transports: ['websocket']은 그냥 웹소켓 방식으로만 통신하라는 뜻이다.
if (!socket && isLoggedIn) {
console.log(!socket && isLoggedIn, '웹소켓 연결을 진행합니다.');
socket = SocketIOClient(`${Config.API_URL}`, {
transports: ['websocket'],
});
}
만일, 서버에 연결되어 있는데 여러 번 계속해서 소켓이 연결되면 한번 요청해도 여러 번 요청이 가고, 여러 번 응답이 올 것이다. 그래서 소켓이 없을 때(!socket)만 연결하도록 로직을 구성한다.
let socket: Socket | undefined;
소켓이 있을 수도 없을 수도..
위랑 아래랑 똑같은 뜻이다.
const useSocket = (): [typeof socket, () => void] => { }
소켓의 타입을 지정하는 똑같은 의미
const useSocket = (): [typeof socket, () => void] => {
const disconnect = useCallback( () =>{
if(socket) {
socket.disconnect();
socket = undefined;
},
}, []);
}
() => void는 아래의 disconnect 함수의 타입을 지정해 주는 것
매개변수로 아무것도 안 받고, 리턴값은 undefined다.
함수의 리턴값을 지정하지 않으면 undefined인데, typescript의 경우 void라고 표현한다.
9강. 실시간 데이터 받기, 로그아웃(Bearer 토큰)
1) 실시간 데이터 받기
hooks에 넣어놨던 useSocket 코드를 AppInner에 넣기
const [socket, disconnect] = useSocket();
useEffect(() => {
const helloCallback = (data: any) => {
console.log(data);
};
if (socket && isLoggedIn) {
console.log(socket);
socket.emit('login', 'hello');
socket.on('hello', helloCallback);
}
return () => {
if (socket) {
socket.off('hello', helloCallback);
}
};
}, [isLoggedIn, socket]);
useEffect(() => {
if (!isLoggedIn) {
console.log('!isLoggedIn', !isLoggedIn);
disconnect();
}
}, [isLoggedIn, disconnect]);
socket.emit('login', 'hello');
socket.on('hello', helloCallback);
서버에게 데이터는 보내는 것 : socket.emit
서버에서 데이터를 받아오는 것 : socket.on
socket.off('hello', helloCallback);
받는 거 그만하기 : socket.off
키=값 또는 키, 값 꼴로 수신
- 키, 값
- 'hello', 'world'
- 'userInfo', { name: 'chobo', address: coder-chobo.tistory.com }
- 'order', { orderId: '1224s', price: 1000, latitude: 37.5, longitude: 123.5 }
useEffect(() => {
const helloCallback = (data: any) => {
console.log(data);
};
if (socket && isLoggedIn) {
socket.on('hello', helloCallback);
}
return () => {
if (socket) {
socket.off('hello', helloCallback);
}
};
}, [isLoggedIn, socket]);
- useEffect의 return 함수는 cleanUp
- socket.on : 연결
- socket.off : 끊기
hello라는 key로 data를 받아올 건데, 위에 나온 부분 중 다음 부분으로 받아오는 것
const helloCallback = (data: any) => {
console.log(data);
};
서버로부터 데이터를 받을 때는 callback 방식으로 처리
즉, 미리 계획되어 있어야 한다. 서버개발자가 서버로부터 hello라는 key로 보내줄 거라고 얘기한 상황이어야 한다.
소켓이 연결되면 서버에 연결되었다고 알림이 뜬다.
1초에 한 번씩 emit이 올라가는데, 이는 back에서 1초에 한번 리턴하라고 코딩이 되었기 때문
이거 오류인 줄 알고 고치려고 몇 시간 봤는데.. 흑흑
연결되면 콜백을 해주도록 해놨기 때문
위에는 hello로 해놨지만 실제로는 key를 서버에 전달하면 주문 내역을 리턴하는 등으로 바꿀 수 있다.
이건 서버 개발자와 약속해서 진행하면 된다.
2) 로그아웃
토큰을 꺼내오기 : state.user.accessTocken
slice의 user.ts안의 토큰을 가져온다.
const initialState = {
name: '',
email: '',
accessToken: '',
};
headers: {
Authorization: `Bearer ${accessToken}`,
},
header도 키값이다.
Authorization Bearer도 서버개발자와 약속이다.
여기서 accessToken을 넣어주면 서버가 나인지 아닌지 판단을 하는 것이다.
dispatch(
userSlice.actions.setUser({
name: '',
email: '',
accessToken: '',
}),
);
setUser에서 초기화해주면 알아서 다 정보가 들어간다.
await EncryptedStorage.removeItem('refreshToken');
refreshToken도 지워줘야(초기화해 줘야) 된다.
그러지 않으면 로그아웃 했다고 해도 로그아웃이 안된다.
앱-서버 불일치가 일어나면 오류가 발생한다.
앱이 오류가 발생하면 서버도 오류가 발생해야 한다.