처음 생각한 다이나믹 헤더 의사 코드
export default function Page({
params,
searchParams,
}: {
params: { slug: string }
searchParams: { [key: string]: string | string[] | undefined }
}) {
return <h1>My Page</h1>
}
- Next.js 에서 slug 와 query string 을 가져올 수 있는 위 코드를 사용해서
- layout.tsx 혹은 page.tsx : (서버컴포넌트 겠죠..? 아마) 에서
- 동적으로 주소에따라 MobileHeader.tsx 컴포넌트로 넘겨주는 props 를 다르게 한다!
위 방법은 동적 라우팅에서만 사용가능! 따라서 middleware 설정 추가
확인해보니 위 방법은 동적 라우팅, 예를 들어 위치가 /trips/[id]
같은 경우에만 사용가능한 것이었습니다.
스태틱한 라우트에서 위와 같이 하고 콘솔에 찍어보니 params 는 빈 객체를, searchParams 는 null 을 반환합니다.
그래서 방법을 찾은 것은, src/utils/supabase/middleware.ts 를 수정하는 방법입니다.
middleware 레벨에서 pathname과 queryParams 를 헤더에 담아 보내주는것이죠.
이를 위해 먼저 middware 에서 헤더를 set 하기로 하였습니다.
// src/utils/supabase/middleware.ts
export async function updateSession(request: NextRequest) {
// 아래 requestHeaders set 관련 로직이, 서버컴포넌트에서 시작하자마자 주소를 알수있게 하는 로직임
// 헤더에 현재 경로 추가
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-pathname', request.nextUrl.pathname);
// 헤더에 특정 쿼리 파리미터(funnel) 값 추가
const funnelParam = request.nextUrl.searchParams.get('funnel');
if (funnelParam) requestHeaders.set('x-funnel', funnelParam);
let supabaseResponse = NextResponse.next({
request: {
headers: requestHeaders
},
});
// ... 중략 ...
위와 같이 middleware 상단에 headers 를 set 하는 로직을 추가하고,
response 에 request { } 로 담아줍니다.
헤더를 가져오는 유틸리티 함수
이제는 그럼 위에서 설정한 headers 를 가져오면 될 것 같습니다.
매 서버컴포넌트 마다 가져오는 코드 세 줄을 써도 되긴 하지만,
편의와 분리를 위해 유틸리티 함수를 작성했습니다.
import { headers } from 'next/headers';
export const getPathnameServer = () => {
const headersList = headers();
const pathname = headersList.get('x-pathname');
const queryParams = headersList.get('x-funnel');
return { pathname, queryParams };
};
이 코드는 헤더에서 pathname 과 queryParams 를 가져오는 역할을 합니다.
각각을 리턴하며 객체 형태로 리턴합니다.
서버컴포넌트에서 사용
이제 이 코드를 layout.tsx, page.tsx 에서 사용하면 됩니다.(주의 반드시 서버컴포넌트이어야 합니다)
const AuthenticatedLayout: React.FC<AuthenticatedLayoutProps> = ({
children,
}) => {
const { pathname, queryParams } = getPathnameServer();
// 아래 콘솔로그를 주석해제 하시면 테스트 해볼 수 있습니다.
// console.log('pathname =============>', pathname);
// console.log('queryParams =============>', queryParams);
// ...중략...
이제 이렇게 가져온 pathname, queryParams 를 사용해 mobileHeader 를 조건부 렌더링 할 수 있습니다.
mobileHeader.tsx
이제 조건부 렌더링을 실제로 할 모바일 헤더가 필요합니다!
type MobileHeaderProps = {
title: string;
close?: boolean;
notification?: boolean;
search?: boolean;
settings?: boolean;
edit?: boolean;
};
const MobileHeader: React.FC<MobileHeaderProps> = ({
title,
close,
notification,
search,
settings,
edit,
}) => {
return (
<header className="h-[57px] w-full flex flex-row items-center px-5">
<div className="w-[calc(100%/3)] flex justify-start items-center">
<Arrow_Back />
</div>
<h1 className="w-[calc(100%/3)] text-center leading-3">{title}</h1>
<div className="w-[calc(100%/3)] flex justify-end items-center gap-2">
{search && <Search />}
{notification && <Notification />}
{settings && <Settings />}
{edit && <span>수정</span>}
{close && <Close />}
</div>
</header>
);
};
export default MobileHeader;
위와 같이 단순하게 prop이 있으면 필요한 아이콘을 렌더링 하고, 없으면 안하는 그러한 컴포넌트입니다.
파라미터는 다음과 같습니다.
- title : string => 헤더 중앙 제목(필수)
- close : boolean => 우측상단 x 버튼을 보여줄지말지(기본값 false)
- notification : boolean => 우측상단 알림 버튼을 보여줄지말지(기본값 false)
- search : boolean => 우측상단 검색돋보기 버튼을 보여줄지말지(기본값 false)
- settings : boolean => 우측상단 세팅즈(톱니바퀴) 버튼을 보여줄지말지(기본값 false)
- edit : boolean => 우측상단 '수정'이라는 글 버튼을 보여줄지말지(기본값 false)
이제 서버컴포넌트에서 자유롭게 사용하시면 될 것 같습니다!
'nextjs' 카테고리의 다른 글
[240731 TIL] Next.js Lazy Loading (0) | 2024.07.31 |
---|---|
[240726 TIL] 컴포넌트와 UI를 반환하는 커스텀 훅 (0) | 2024.07.26 |
[240717 TIL] Next.js Sharp (0) | 2024.07.17 |
[240716 TIL] NextJs Pwa (0) | 2024.07.16 |
[240715 TIL] Supabase 인증인가 with NextJs 3편 (0) | 2024.07.15 |