From df309bfe16ed7edc98d8619fdb629e6f0f333ea6 Mon Sep 17 00:00:00 2001 From: hyeon-9yu Date: Sun, 5 Sep 2021 14:28:52 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20useInput=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=ED=9B=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .babelrc | 10 ++++------ src/hooks/useInput.js | 12 ++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 src/hooks/useInput.js diff --git a/.babelrc b/.babelrc index ec29cf4..28b1125 100644 --- a/.babelrc +++ b/.babelrc @@ -1,8 +1,5 @@ { - "presets": [ - "@babel/preset-env", - "@babel/preset-react" - ], + "presets": ["@babel/preset-env", "@babel/preset-react"], "plugins": [ "@babel/plugin-transform-runtime", [ @@ -15,9 +12,10 @@ "@styles": "./src/styles", "@views": "./src/views", "@utils": "./src/utils", - "@components": "./src/components" + "@components": "./src/components", + "@hooks": "./src/hooks" } } ] ] -} \ No newline at end of file +} diff --git a/src/hooks/useInput.js b/src/hooks/useInput.js new file mode 100644 index 0000000..2407521 --- /dev/null +++ b/src/hooks/useInput.js @@ -0,0 +1,12 @@ +import { useCallback, useState } from 'react'; + +const useInput = initialData => { + const [value, setValue] = useState(initialData); + + const handler = useCallback(e => { + setValue(e.target.value); + }, []); + return [value, handler, setValue]; +}; + +export default useInput; From 2d25dc779099199864b7537e304dc1ef9403120d Mon Sep 17 00:00:00 2001 From: hyeon-9yu Date: Sun, 5 Sep 2021 14:30:20 +0900 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20=EC=86=8C=EC=BC=93=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20=EC=83=81=ED=96=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c92f73c..70a2f96 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "recoil": "^0.1.3", "sass": "^1.32.8", "sass-loader": "^11.0.1", - "socket.io-client": "2.3.1", + "socket.io-client": "^4.1.3", "style-loader": "^2.0.0", "swr": "^0.5.6", "uuid": "3.4.0", From 7d6780ffde45bec0b35469beaaa559d5c942e812 Mon Sep 17 00:00:00 2001 From: hyeon-9yu Date: Sun, 5 Sep 2021 14:31:32 +0900 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20chatroom=20route=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 4 ++-- src/utils/api.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 04277da..f94ccec 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -27,8 +27,8 @@ function App() { - - + + diff --git a/src/utils/api.js b/src/utils/api.js index 4628574..8952681 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -66,7 +66,7 @@ export const API_UPDATE_LECTURES = makeAPI(PATCH, '/lecture'); export const API_GET_HISTORIES = makeAPI(GET, '/history'); const axiosInstance = axios.create({ - baseURL: 'http://localhost:2021/api', + baseURL: `${API_URL_BASE}/api`, timeout: 20000, }); From 318949cd22c0bfe505149f86df3febb25552e6b5 Mon Sep 17 00:00:00 2001 From: hyeon-9yu Date: Sun, 5 Sep 2021 14:32:26 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20chatroom=20selector=20+=20suspense?= =?UTF-8?q?=EB=A1=9C=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/states/Chatroom.js | 30 ++++++-- src/views/chat/chatroom.jsx | 105 +++++++-------------------- src/views/chat/index.jsx | 17 ++--- src/views/chatrooms/chatroomList.jsx | 60 +++++++-------- 4 files changed, 90 insertions(+), 122 deletions(-) diff --git a/src/states/Chatroom.js b/src/states/Chatroom.js index 8fe7692..fc35e05 100644 --- a/src/states/Chatroom.js +++ b/src/states/Chatroom.js @@ -1,10 +1,30 @@ -import { atom } from 'recoil'; +import { atom, selectorFamily } from 'recoil'; +import { API_FIND_CHATROOM, API_GET_MESSAGES, requestAPI } from '../utils/api'; const chatroomState = atom({ key: 'chatroomList', - default: [] + default: [], }); -export { - chatroomState, -}; +const messagesState = atom({ + key: 'messageList', + default: [], +}); + +const emptyMsg = atom({ + key: 'emptyMsg', + default: null, +}); + +const currentChatRoom = selectorFamily({ + key: 'currentChatRoom', + get: chatRoomId => async () => { + const { data: chatRoom } = await requestAPI(API_FIND_CHATROOM().setPathParam(chatRoomId)); + const { data: messages } = await requestAPI( + API_GET_MESSAGES().setQuery({ chatRoomId, start: 0, end: 10 }), + ); + return { chatRoom, messages }; + }, +}); + +export { messagesState, chatroomState, emptyMsg, currentChatRoom }; diff --git a/src/views/chat/chatroom.jsx b/src/views/chat/chatroom.jsx index 8a4e865..7c947cf 100644 --- a/src/views/chat/chatroom.jsx +++ b/src/views/chat/chatroom.jsx @@ -1,31 +1,38 @@ import React, { useEffect, useRef, useState } from 'react'; import ContentEditable from 'react-contenteditable'; -import { Menu, MenuItem, Button, Container, makeStyles, Typography } from '@material-ui/core'; +import { Button, Container, makeStyles, Typography } from '@material-ui/core'; import IconButton from '@material-ui/core/IconButton'; import MoreVertIcon from '@material-ui/icons/MoreVert'; import ExitToAppIcon from '@material-ui/icons/ExitToApp'; +import { Redirect, useHistory, useParams } from 'react-router-dom'; +import { useRecoilValue } from 'recoil'; +import useInput from '@hooks/useInput'; import { v4 as uuidv4 } from 'uuid'; -import { API_FIND_CHATROOM, API_GET_MESSAGES, API_GET_POINTS, requestAPI } from '../../utils/api'; +import usersIcon from '@img/fontawesome/chat-users.svg'; +import userIcon from '@img/fontawesome/chat-user.svg'; import { StatusCodes } from 'http-status-codes'; +import { uosYellow } from '@utils/styles/Colors'; import ChatMessage from './chatMessage'; +import { API_GET_MESSAGES, requestAPI } from '../../utils/api'; import { getSocket } from '../../utils/socket'; -import { Redirect, useHistory } from 'react-router'; -import { uosYellow } from '@utils/styles/Colors'; import UserInfoDialog from '../../components/UserInfoDialog'; -import userIcon from '@img/fontawesome/chat-user.svg'; -import usersIcon from '@img/fontawesome/chat-users.svg'; import RoomInfoMenu from './RoomInfoMenu'; import MainMenu from './MainMenu'; +import { currentChatRoom } from '../../states/Chatroom'; -export default function Chatroom({ id }) { - const [chatRoom, setChatRoom] = useState({}); - const [messages, setMessages] = useState([]); +export default function Chatroom() { + const { chatRoomId } = useParams(); + const { chatRoom: initChatRoom, messages: initMessages } = useRecoilValue( + currentChatRoom(chatRoomId), + ); + const [messages, setMessages] = useState(initMessages); + const [chatRoom, setChatRoom] = useState(initChatRoom); const [readPoints, setReadPoints] = useState([]); const [emptyMsg, setEmptyMsg] = useState(''); const [infoOpen, setInfoOpen] = useState(false); const [menuAnchorEl, setMenuAnchorEl] = useState(null); const [infoAnchorEl, setInfoAnchorEl] = useState(null); - const [input, setInput] = useState(''); + const [input, handleInput, setInput] = useInput(''); const classes = useStyles(); @@ -47,7 +54,6 @@ export default function Chatroom({ id }) { if (!userId) { return ; } - const chatRoomId = id; const socket = getSocket(); const menuOption = ['채팅방 이름 변경', '참여자 목록', '채팅방 나가기']; const loadUnit = 100; @@ -77,8 +83,8 @@ export default function Chatroom({ id }) { messageRef.current = newMessages; socket.emit('read', { - chatRoomId: chatRoomId, - userId: userId, + chatRoomId, + userId, messageIdx: range.current.end, }); }; @@ -115,64 +121,11 @@ export default function Chatroom({ id }) { socket.on('message', onMessageEvent); socket.on('read', onReadEvent); - const getChatRoom = async chatRoomId => { - const response = await requestAPI(API_FIND_CHATROOM().setPathParam(chatRoomId)); - - if (response.status !== StatusCodes.OK) { - setEmptyMsg('데이터를 불러오는데 실패했습니다.'); - - history.push('/chatrooms'); - - throw new Error(); - } - - setChatRoom(response.data); - chatRoomRef.current = response.data; - - return response.data; - }; - - const getMessages = async (chatRoomId, start, end) => { - if (end < 0) return; - - const response = await requestAPI(API_GET_MESSAGES().setQuery({ chatRoomId, start, end })); - - if (response.status !== StatusCodes.OK) { - setEmptyMsg('채팅을 불러오는데 실패했습니다.'); - return; - } - setMessages(response.data); - messageRef.current = response.data; - }; - - const getReadPoints = async chatRoomId => { - const response = await requestAPI(API_GET_POINTS().setQuery({ chatRoomId })); - - if (response.status !== StatusCodes.OK) { - setEmptyMsg('데이터를 불러오는데 실패했습니다.'); - return; - } - setReadPoints(response.data); - readPointRef.current = response.data; - }; - - getChatRoom(chatRoomId) - .then(room => { - const start = room.length > loadUnit ? room.length - loadUnit : 0; - const end = room.length > 0 ? room.length - 1 : 0; - - range.current = { start, end }; - - getMessages(chatRoomId, start, end); - getReadPoints(chatRoomId); - - socket.emit('read', { - chatRoomId: chatRoomId, - userId: userId, - messageIdx: range.current.end, - }); - }) - .catch(() => {}); + socket.emit('read', { + chatRoomId, + userId, + messageIdx: 10, + }); return () => { socket.off('read'); @@ -186,10 +139,6 @@ export default function Chatroom({ id }) { document.execCommand('insertText', false, text); }; - const onChange = e => { - setInput(e.target.value); - }; - const onEnterPress = e => { if (e.key === 'Enter') { e.preventDefault(); @@ -208,7 +157,6 @@ export default function Chatroom({ id }) { type: 'normal', content: input, }; - socket.emit('message', messageEvent); const newMessages = messageRef.current.concat(messageEvent); @@ -348,7 +296,7 @@ export default function Chatroom({ id }) { tagName="div" html={input} onPaste={onPaste} - onChange={onChange} + onChange={handleInput} onKeyPress={onEnterPress} />