-
7. Optimistic UpdatePS 2024. 7. 22. 21:13
https://www.youtube.com/watch?v=-xXASlyU0Ck&t=2007s
를 보며 실습하는 영상
---
저번에 메세지를 데이터베이스에 저장하고 표시하는 것까지 해줬다. 아직 소켓통신을 하지 않기에 데이터를 인서트하고 새로고침을 하고 데이터를 다시 받아와야지 내가 입력한 메세지가 나온다.
그런데, 이렇게 데이터를 입력하고 다시 받아오기까지 시간이 좀 걸리기에, 내가 이런 이런 입력을 하면 당연히 DB에 저장될 걸로 가정하고, 내 화면에 바로 입력값을 표시해주는 방법이 있다. optimistic update라고 하는데
https://react.dev/reference/react/useOptimistic
여기서 자세한 내용을 볼 수 있다.
This state is called the “optimistic” state because it is usually used to immediately present the user with the result of performing an action, even though the action actually takes time to complete.
뭐, 좋아요나 이런거에도 쓰인다.
여기서 이걸 한번 써보자.
메세지를 입력하고 엔터를 누르면 내가 누른 메세지가 바로 표시되게끔 해보자!
먼저 uuid 라이브러리를 설치해준다.
https://www.npmjs.com/package/uuid
그리고 components/ChatInput.tsx에서 임포트 해준다.
npm i uuid
그럼 빨간줄이 그이면서 못쓴다고 할텐데, 타입스크립트이기 때문에 타입이 필요하다. 타입도 임포트 해준다.
npm i --save-dev @types/uuid
그리고 ChatInput.tsx 파일을 고쳐준다.
"use client"; import React from "react"; import { Input } from "./ui/input"; import { createClient } from "@/utils/supabase/client"; import { toast } from "sonner"; import { v4 as uuidv4 } from "uuid"; // uuid import import { useUser } from "@/lib/store/user"; // user 정보를 불러온다. export const ChatInput = () => { const supabase = createClient(); const user = useUser((state) => state.user); // user 정보를 불러온다. // 메세지 전송 펑션 const handleSendMessage = async (text: string) => { // optimistic update를 해줄 message const newMessage = { id: uuidv4(), text, user_id: user?.id, is_edit: false, created_at: new Date().toISOString(), users: { id: user?.id, avatar_url: user?.user_metadata.avatar_url, created_at: new Date().toISOString(), display_name: user?.user_metadata.user_name, }, }; const { data, error, status } = await supabase .from("messages") .insert({ text }); if (error) { toast.error(error.message); } }; return ( <div className="p-5"> <Input placeholder="send message" onKeyDown={(e) => { if (e.key === "Enter") { // enter 키를 누르면 메세지가 전송되도록 handleSendMessage(e.currentTarget.value); e.currentTarget.value = ""; // 메세지를 전송하고 나서 칸을 비워준다. } }} /> </div> ); };
보면은 handleSendMessage에 optimistic update를 해줄 newMessage 객체를 만든걸 볼 수 있다.
이제 lib/store/messages.ts로 가서 addMessage라는 펑션을 추가해주도록 한다.
// lib/store/message.ts import { create } from "zustand"; export type IMessage = { created_at: string; id: string; is_deleted: string | null; is_edit: boolean; text: string; user_id: string; users: { avatar_url: string; created_at: string; deleted_at: string | null; display_name: string; id: string; updated_at: string | null; } | null; }; interface MessageState { messages: IMessage[]; addMessage: (message: IMessage) => void; } export const useMessage = create<MessageState>()((set) => ({ messages: [], addMessage: (message) => set((state) => ({ messages: [...state.messages, message] })), // 기존 state에 담겨있던 message들 + 이번에 작성한 메세지 }));
그리고 다시 component/ChatMessage.tsx 파일로 돌아와 완성해준다.
"use client"; import React from "react"; import { Input } from "./ui/input"; import { createClient } from "@/utils/supabase/client"; import { toast } from "sonner"; import { v4 as uuidv4 } from "uuid"; // uuid import import { useUser } from "@/lib/store/user"; // user 정보를 불러온다. import { IMessage, useMessage } from "@/lib/store/messages"; export const ChatInput = () => { const supabase = createClient(); const user = useUser((state) => state.user); // user 정보를 불러온다. const addMessage = useMessage((state) => state.addMessage); // addMessage function을 불러온다. // 메세지 전송 펑션 const handleSendMessage = async (text: string) => { // 빈 메세지가 오지 못하도록 처리 if (!text.trim().length) { toast.error("Message cant not be empty"); return; } // optimistic update를 해줄 message const newMessage = { id: uuidv4(), text, user_id: user?.id, is_edit: false, created_at: new Date().toISOString(), users: { id: user?.id, avatar_url: user?.user_metadata.avatar_url, created_at: new Date().toISOString(), display_name: user?.user_metadata.user_name, }, }; const { data, error, status } = await supabase .from("messages") .insert({ text }); addMessage(newMessage as IMessage); // 불러온 addMessage 펑션 사용하기 if (error) { toast.error(error.message); } }; return ( <div className="p-5"> <Input placeholder="send message" onKeyDown={(e) => { if (e.key === "Enter") { // enter 키를 누르면 메세지가 전송되도록 handleSendMessage(e.currentTarget.value); e.currentTarget.value = ""; // 메세지를 전송하고 나서 칸을 비워준다. } }} /> </div> ); };
이제 메세지를 입력하고 엔터를 눌러보면 바로바로 화면에 내가 입력한 메세지가 나오는 걸 볼 수 있다.
물론 Supabase DB에서 봐도, 데이터가 들어간 걸 볼 수 있다.
github : https://github.com/Wunhyeon/Next-Supabase-Chat/tree/7.OptimisticUpdate
'PS' 카테고리의 다른 글
BOJ 15989 - 1, 2, 3 더하기 4 (0) 2024.07.30 BOJ 12919 A와 B 2 (6) 2024.07.23 BOJ 9655 돌게임 (0) 2024.07.11 플로이드 워셜. BOJ 11404 (0) 2024.07.08 BOJ 16568 (1) 2024.07.08