애플리케이션 상단에 배치될 헤더 컴포넌트를 구성합니다.
Header.jsx
알림(notification) 상태를 관리하기 위한 데이터를 아래와 같이 구성합니다.
const initialNotifications = [
{ id: 1, content: '"yamoo9"님 회원 가입을 환영합니다.' },
{ id: 2, content: '"lovelyU"님이 새로운 글을 등록했습니다.' },
{ id: 3, content: '"liketiger님이 "친구 요청" 하습니다.' },
{ id: 4, content: '"likelion"님이 "좋아요!"를 누르셨습니다.' },
];
알림 상태를 표시하거나 감추는 상태와 알림 내용 집합을 관리할 상태를 설정합니다. 그리고 조건부 렌더링이 되도록 JSX 마크업을 아래와 같이 구성합니다.
import { useState, useCallback } from 'react';
import NotificationTray from './NotificationTray';
function Header() {
const [showNotifications, setShowNotifications] = useState(false);
const [notificationContent, setNotificationContent] = useState(initialNotification);
const handleToggleNotification = () => setShowNotifications((sn) => !sn);
const handleDeleteNotification = useCallback(
(deleteId) => () => {
setNotificationContent(
contents => contents.filter(({ id }) => id !== deleteId)
);
},
[]
);
const label = `알림 ${showNotification ? '감춤' : '표시'}`;
return (
<header>
<h1>
<a href="/" className="homeLink">브랜드</a>
</h1>
<nav className="navigation">
<h2 className="sr-only">페이지 탐색</h2>
<ul>
<li>
<button
type="button"
aria-label={label}
title={label}
onClick={handleToggleNotification}
className="notificationToggleButton"
>
<svg
fill="none"
viewBox="0 0 20 21"
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
d="M10 3.464V1.1m0 2.365a5.338 5.338 0 015.133 5.368v1.8c0 2.386 1.867 2.982 1.867 4.175C17 15.4 17 16 16.462 16H3.538C3 16 3 15.4 3 14.807c0-1.193 1.867-1.789 1.867-4.175v-1.8A5.338 5.338 0 0110 3.464zM4 3L3 2M2 7H1m15-4l1-1m1 5h1M6.54 16a3.48 3.48 0 006.92 0H6.54z"
/>
</svg>
</button>
</li>
</ul>
</nav>
{
showNotifications && (
<NotificationTray
notificationContent={notificationContent}
onDelete={handleDeleteNotification}
/>
)
}
</header>
);
}
그리고 NotificationTray 컴포넌트를 작성합니다. 외부에서 전달된 속성(props)을 사용해 리스트 렌더링 하거나, 이벤트에 반응할 수 있도록 구성합니다.
NotificationTray.jsx
function NotificationTray({
notificationContent,
onDelete,
}) {
return (
<div className="NotificatonTray">
<ul>
{notificationContent.map(({ id, content }) => (
<li key={id}>
<span>{content}</span>
<button
type="button"
className="clearButton"
aria-label="알림 삭제"
title="알림 삭제"
onClick={onDelete(id)}
>
<svg
width={16}
height={16}
viewBox="0 0 512 512"
fill="currentColor"
strokeWidth={0}
>
<path
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="32"
d="M368 368L144 144m224 0L144 368"
/>
</svg>
</button>
</li>
))}
</ul>
</div>
);
}
마지막으로 App (또는 RootLayout) 컴포넌트에서 Header 컴포넌트를 눌러와 화면에 렌더링합니다.
App.jsx
import Header from './Header';
function App() {
return (
<>
<Header />
</>
);
}
export default App;