Tạo modal với Nextjs 14
- Tạo context API: xử lý kèm logic:
"use client";
import { $ModalKeys } from "@/collects/modals";
import {
Dispatch,
PropsWithChildren,
SetStateAction,
createContext,
useState,
} from "react";
type $ToggleFn = { key: $ModalKeys; data?: any };
type $Show = {
[T in $ModalKeys]: {
open: boolean;
data?: any;
};
};
type $_Modal = {
onToggle: (props: $ToggleFn) => void;
show: $Show;
setShow: Dispatch<SetStateAction<$Show>>;
};
export let _$modal = {} as $_Modal;
const useLogic = () => {
const [show, setShow] = useState({} as $Show);
const onToggle = (props: $ToggleFn) => {
const { key, data } = props;
setShow((prev) => ({
...prev,
[key]: { ...prev[key], open: !prev[key]?.open, data },
}));
};
_$modal = {
onToggle,
show,
setShow,
};
return { onToggle, show, setShow };
};
type ValueCtx = ReturnType<typeof useLogic>;
export const ModalCtx = createContext({} as ValueCtx);
export const ModalProvider = ({ children }: PropsWithChildren) => {
const valueCtx = useLogic();
return (
<ModalCtx.Provider value={{ ...valueCtx }}>
<>{children}</>
</ModalCtx.Provider>
);
};
- Tạo Component Modal :
"use client";
import cx from "classnames";
import React, { useContext } from "react";
import ReactDOM from "react-dom";
import styles from "./styles.module.scss";
import { ModalCtx } from "./context";
export type $Modal = {
open?: boolean;
onToggle: () => void;
data?: any;
};
type $Props = {
set?: {
open?: $Modal["open"];
isCloseOutside?: boolean;
clsOverlay?: string;
clsModal?: string;
content?: (props: $Modal) => JSX.Element;
header?: (props: $Modal) => JSX.Element;
};
action: {
onToggle: () => void;
};
};
export default function Modal(props: $Props) {
const { set, action } = props;
const {} = useContext(ModalCtx);
if (!set?.open) {
return null;
}
return ReactDOM.createPortal(
<div
className={cx(styles.overlay, set?.clsOverlay)}
onClick={set?.isCloseOutside ? action?.onToggle : undefined}
>
<div className={cx(styles.modal, set?.clsModal)} onClick={onStopPrpg}>
{set?.header?.({ onToggle: action.onToggle })}
{set.content?.({ onToggle: action.onToggle })}
</div>
</div>,
document.body
);
}
const onStopPrpg = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
event.stopPropagation();
event.preventDefault();
};
- Tạo SCSS : file styles.module.scss
.overlay {
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
display: flex;
align-items: center;
justify-content: center;
.modal {
background-color: lightblue;
display: flex;
flex-direction: column;
width: fit-content;
border-radius: 0.5rem;
padding: 1rem;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
.header {
display: flex;
}
}
}
Đơn giản đúng hông, có thể tuỳ chỉnh styles tuỳ thích. Phần tiếp theo là Dropbox
All rights reserved