Zustand를 사용해서 모달 상태를 간단하고 효율적으로 관리할 수 있다. Zustand는 경량 상태 관리 라이브러리로, 전역 상태와 모달의 열림/닫힘 상태 관리에 적합하다.
1. Zustand 스토어를 설정해서 모달의 상태와 상태 변경 함수를 정의한다.
import create from 'zustand';
interface ModalState {
isOpen: boolean;
openModal: () => void;
closeModal: () => void;
}
const useModalStore = create<ModalState>((set) => ({
isOpen: false,
openModal: () => set({ isOpen: true }),
closeModal: () => set({ isOpen: false }),
}));
export default useModalStore;
2. 설정한 Zustand 스토어를 사용해서 모달의 열림/닫힘 상태를 제어한다.
import React from 'react';
import useModalStore from '../store/useModalStore';
const Modal = () => {
const { isOpen, closeModal } = useModalStore();
if (!isOpen) return null;
return (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
<div className="bg-white p-6 rounded shadow-md">
<h2 className="text-lg font-bold">Modal Title</h2>
<p>이것은 모달 내용입니다.</p>
<button
onClick={closeModal}
className="mt-4 px-4 py-2 bg-blue-500 text-white rounded"
>
닫기
</button>
</div>
</div>
);
};
export default Modal;
3. Shadcn/ui dialog 에서 사용하기
Dialog의 기본 닫기 버튼(DialogClose)을 사용하도록 변경하려면, 커스텀 닫기 버튼을 제거하고 DialogClose를 활용하면된다. 기본 닫기 버튼은 Radix UI 기반으로 제공되며, shadcn/ui에서 이미 스타일이 적용되어 있기 때문에 추가 작업 없이 바로 사용할 수 있다. 이렇게 편할 수가.
- onOpenChange는 상태를 관리하는 openModal 및 closeModal 함수와 동기화되어, 기본 닫기 버튼을 클릭해도 상태가 업데이트된다.
'use client';
import React, { useState } from 'react';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogClose,
} from "@/components/ui/dialog";
import ChatList from './ChatList';
import ChatRoom from './ChatRoom';
import useModalStore from '../store/modalStore';
const ChatModal = () => {
const { isOpen, openModal, closeModal } = useModalStore();
const [activeTab, setActiveTab] = useState<'list' | 'room'>('list');
const [activeChatroomId, setActiveChatroomId] = useState<string | null>(null);
return (
<>
{/* 플로팅 채팅 버튼 */}
<button
className="fixed bottom-5 right-5 p-4 bg-blue-600 text-white rounded-full shadow-lg focus:outline-none"
onClick={openModal}
>
💬
</button>
{/* 채팅 모달 */}
<Dialog open={isOpen} onOpenChange={(open) => (open ? openModal() : closeModal())}>
<DialogContent>
{/* 모달 헤더 */}
<DialogHeader>
<DialogTitle>Chat</DialogTitle>
<DialogClose className="text-gray-500 hover:text-gray-700 focus:outline-none" />
</DialogHeader>
{/* 탭 */}
<div className="flex border-b">
<button
className={`flex-1 py-2 text-center ${
activeTab === 'list' ? 'border-b-2 border-blue-500 font-semibold' : ''
}`}
onClick={() => setActiveTab('list')}
>
채팅 리스트
</button>
<button
className={`flex-1 py-2 text-center ${
activeTab === 'room' ? 'border-b-2 border-blue-500 font-semibold' : ''
}`}
onClick={() => setActiveTab('room')}
>
채팅방
</button>
</div>
{/* Content */}
<div className="flex-1 overflow-y-auto">
{activeTab === 'list' ? (
<ChatList onSelectChatroom={setActiveChatroomId} />
) : (
<ChatRoom chatroomId={activeChatroomId} />
)}
</div>
</DialogContent>
</Dialog>
</>
);
};
export default ChatModal;
'스파르타코딩클럽 > 내일배움캠프' 카테고리의 다른 글
postgres_changes로 전달된 데이터 타입 (0) | 2024.12.27 |
---|---|
렌더링 패턴 (0) | 2024.12.17 |
[Typescript] (1) | 2024.12.12 |
[Next.js] 주요 렌더링 패턴 (1) | 2024.12.10 |
[React] 필터링 및 결과 리스트 렌더링 (0) | 2024.11.28 |