Modal mit Next.js und Zustand
Next.js bzw. React.js stehen für reaktives Web. Obwohl React bereits von Haus aus vieles mitbringt, kann es schwierig sein, eine passende und globale Architektur aufzubauen – So auch für ein Komponentenübergreifendes Modal bzw. einen Dialog. Die Lösung bietet Zustand.
Installation
Zu Beginn installieren wir Zustand in unserem Projekt:
npm install zustand
Store erstellen
Wenn wir Zustand in unser Projekt installiert haben, müssen wir zuerst einen Store erstellen. Der Store ist eine Art Speicher, welcher Daten über mehrere Komponenten hinweg speichert und beibehält. So können wir z.B. eine Variable in Komponente A ändern, welche in Komponente B verwendet wird.
import { create } from 'zustand';
const useModalStore = create((set) => ({
open: false,
setOpen: (status) => set({ open: status }),
}));
export default useModalStore;
In dem Code oben erstellen wir einen Store mit dem Namen useModalStore
. Das Objekt beinhaltet nur eine Variable open
und eine Funktion, welche diese verändert setOpen
. Mehr brauchen wir auch nicht.
Unser konkreter Ansatz ist nun folgender: Wir setzen in einer Komponente A (z.B. einem Button) die Variable open
im Store auf true
. In der Modal-Komponente fragen wir den Wert ab und öffnen oder schließen (je nach Wert) das Modal.
Modal öffnen
Wie zuvor beschrieben wollen wir das Modal nun innerhalb einer Komponente (z.B. einer Kontakt-Sektion) öffnen. Dazu importieren wir den Store und setzen den Wert von open
auf true
.
'use client';
import useModalStore from '@/lib/store/modalStore';
export default function Contact() {
const { open, setOpen } = useModalStore();
return (
<section className="min-h-screen flex items-center">
<div className="max-w-xl mx-auto text-center py-20">
{/* ... */}
<button
className="mt-10 rounded-md bg-indigo-600 text-white px-3.5 py-2.5 shadow-sm hover:bg-indigo-500 text-sm"
onClick={() => {
setOpen(true);
}}
>
Modal öffnen
</button>
</div>
</section>
);
}
Wie zuvor beschrieben ändern wir den Status im Store. Dazu importieren wir diesen zunächst. Die useModalStore()
gibt uns sowohl die Variable als auch die Set-Funktion zurück. In der oberen Komponente rufen wir die Funktion setOpen()
auf und übergeben den Wert true
.
Modal darstellen
Nun müssen wir in der Modal-Komponente nur noch den Wert von open abfragen und das Modal entsprechend öffnen oder schließen.
'use client';
import useModalStore from '@/lib/store/modalStore';
export default function Modal() {
const { open, setOpen } = useModalStore();
return (
<>
{open && (
<div className="fixed top-0 left-0 size-full bg-gray-500 bg-opacity-75 flex items-center justify-center">
<div className="fixed rounded-lg bg-white p-6 shadow-xl max-w-sm w-full text-center">
{/* .... */}
<button
className="w-full mt-8 rounded-md bg-indigo-600 text-white px-3.5 py-2.5 shadow-sm hover:bg-indigo-500 text-sm"
onClick={() => {
setOpen(false);
}}
>
Modal schließen
</button>
</div>
</div>
)}
</>
);
}
In der Modal-Komponenten importieren wir zunächst wieder den Store. Anschließen fragen wir open
ab und rendern das Modal, sofern der Wert true
ist. Bei einem Klick auf dem Button “Modal schließen” setzen wir den Wert mit der Set-Funktion wieder auf false
– Das Modal ist damit wieder geschlossen.
Hinweis: Es ist wichtig, dass wir die Modal-Komponente global importieren (z.B. in ein Layout oder eine Seite).
Zusammenfassung
Mit dem Komponenten übergreifenden State-Management auf Basis von Zustand haben wir es geschafft, eine einfache Architektur zu bauen, mit der wir ein Modal bzw. Overlay öffnen und schließen können – Und das auf der ganzen Seite.