일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 머신러닝기초
- Vue
- 컨트렉트 동일한 함수이름 호출
- 러스트 기초 학습
- vue기초
- ethers websocket
- git rebase
- rust 기초
- 컨트렉트 배포 자동화
- 러스트기초
- ethers type
- SBT표준
- 스마트컨트렉트테스트
- Vue.js
- ethers v6
- chainlink 설명
- 오블완
- ethers typescript
- 스마트컨트렉트 예약어 함수이름 중복
- 체인의정석
- erc4337
- 러스트 기초
- multicall
- erc4337 contract
- 티스토리챌린지
- 계정추상화
- 스마트 컨트렉트 함수이름 중복
- ethers
- 스마트컨트렉트 함수이름 중복 호출
- ambiguous function description
- Today
- Total
체인의정석
[React+Next+typescript+rainbow wallet] 관리자 페이지 만들고 rainbow wallet 붙이기 (블록체인 앱 관리자 페이지 만들기) 본문
[React+Next+typescript+rainbow wallet] 관리자 페이지 만들고 rainbow wallet 붙이기 (블록체인 앱 관리자 페이지 만들기)
체인의정석 2025. 3. 27. 13:471. 관리자 페이지 기본 템플릿다운로드 순서
1. 템플릿
https://tailadmin.com/download
Download Free Tailwind Admin Template - TailAdmin
Download TailAdmin Now Select your preferred option below to start Download and Kickstart your journey.
tailadmin.com
2. 버전 조정
npm install react@18.2.0 react-dom@18.2.0
npm install
3. 실행
npm run dev
2. Next.js의 페이지 라우팅 (관리자 페이지 추가 및 제거)
Next.js의 App Router는 아래 우선순위 규칙에 따라 라우팅을 결정합니다:
1️⃣ app/page.tsx가 있으면 → / 경로는 무조건 이걸 사용
2️⃣ app/page.tsx가 없고,
- 가장 **루트에 가까운 page.tsx**가
- 괄호 폴더((admin) 등) 아래에 있다면
➡ 해당 파일이 자동으로 루트(/) 경로의 페이지 역할을 하게 됩니다.
*참고로 괄호로 된 파일 명은 라우팅 경로에 포함되지 않는다. 위의 예제에서는 src/app/admin 경로에 있는 page.tsx가 루트에 가장 가까운 page.tsx이기 때문에 제일 처음 랜더링 되게 된다.
src/
└── app/
├── (admin)/
│ └── page.tsx ✅ 라우팅 그룹이지만, 루트에 가장 가까운 page.tsx
└── layout.tsx ← 전체 앱에 공통 적용
다음과 같이 next.js에서는 기본적인 라우팅이 되기 때문에 기존 관리자 페이지의 페이지를 추가하거나 제거하려면 위의 규칙에 맞추어서 경로만 설정해 준다면 알아서 라우팅이 되게 됩니다.
Layout.tsx를 사용한 공통 페이지 레이아웃 설정
🧱 layout.tsx란?
Next.js App Router에서 페이지 그룹에 공통으로 적용되는 UI 구조를 설정하는 파일입니다.
✅ 기본 구조 예시
src/app/
├── layout.tsx ← 전체 앱의 글로벌 레이아웃
├── page.tsx
├── (admin)/
│ ├── layout.tsx ← 관리자 전용 레이아웃
│ └── dashboard/
│ └── page.tsx ← 관리자 대시보드 페이지
└── login/
└── page.tsx ← 로그인 전용
- 이 layout.tsx는 해당 디렉터리 아래 모든 page.tsx에 공통 적용됩니다.
🎯 사용 목적
🌍 공통 레이아웃 적용 | Header, Footer, Sidebar |
🎨 테마 적용 | 다크모드, Tailwind 클래스 래핑 등 |
🔒 인증 보호 | 로그인 여부 확인 후 children 제한 |
⚙️ 상태 제공 | ThemeProvider, QueryClientProvider, RecoilRoot 등 |
🧠 특징 요약
계층적으로 중첩 가능 | app/layout.tsx, (admin)/layout.tsx, (auth)/layout.tsx 등 |
서버 컴포넌트 | 기본적으로 Server Component로 동작 ("use client" 안 붙임) |
children 필수 | 내부에 렌더링될 page.tsx가 children으로 전달됨 |
라우팅 그룹에도 적용 가능 | 괄호 폴더((admin) 등) 안에도 layout.tsx 둘 수 있음 |
여기서 다루는 관리자 페이지 또한 기본 layout에 맞추어서 모든 경로에 sidebar와 footer, header등을 두었으며
이에 따라 각 컴포넌트를 변경하면 모든 페이지의 요소들이 변경되게 된다.
3. HOOK에 대한 개념
✅ Hook이란?
Hook은 함수형 컴포넌트에서 React의 기능들을 “붙여서” 사용할 수 있게 하는 함수입니다.
📌 대표적인 예:
useState | 컴포넌트 내 상태값 관리 |
useEffect | 컴포넌트 생명주기 관리 (side effect) |
useContext | Context API 접근 |
useRef | DOM 참조 또는 값 기억 |
useCallback | 함수 메모이제이션 |
useMemo | 값 메모이제이션 |
✅ 커스텀 Hook | 여러분이 직접 만든 재사용 가능한 로직 |
✅ Hook은 어디에 써야 할까?
✅ 정답: 함수형 컴포넌트 내부에서만 사용해야 합니다.
// ✅ 올바른 예
export default function MyComponent() {
const [count, setCount] = useState(0); // Hook 사용
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
이처럼 hook을 만들어서 사용한다면 함수형 컴포넌트의 최상단에서 이 hook을 가져오고 사용을 하면 됩니다.
각 요소인 컴포넌트에서 특정 함수를 실행시키고 싶다면 특정 함수를 hook으로 만들고 가져와서 사용하면 됩니다.
자체적으로 만든 커스텀 Hook의 사용예시는 다음과 같습니다.
import useSomething from '@/hooks/useSomething';
export default function SomeComponent() {
const { value, setValue } = useSomething();
return <div>{value}</div>;
}
✅ Hook을 컴포넌트에 "넣어서 쓰는 것"이 맞을까?
네, 맞습니다. Hook은 "컴포넌트 안에서 호출해서 사용하는 것"이 올바른 방식입니다.
💡 Hook = "이 컴포넌트가 작동할 때, 함께 작동해야 하는 기능 묶음"
→ 그래서 컴포넌트가 mount/unmount 될 때도 같이 관리됩니다.
응용 : 관리자 페이지에 블록체인 지갑을 붙이고 서명하는 hook만들기
먼저 최상단 페이지의 layout.tsx에 rainbow wallet을 추가시켜줍니다.
추가시키는 방법은 rainbow wallet docs에서 확인한 후 사용할 수 있습니다.
https://www.rainbowkit.com/docs/installation
Installation — RainbowKit
Get up and running with RainbowKit
www.rainbowkit.com
먼저 npm install을 해줍니다.
npm install @rainbow-me/rainbowkit wagmi viem@2.x @tanstack/react-query
이후 import 부분을 진행합니다.
...
import { getDefaultConfig } from '@rainbow-me/rainbowkit';
const config = getDefaultConfig({
appName: 'My RainbowKit App',
projectId: 'YOUR_PROJECT_ID',
chains: [mainnet, polygon, optimism, arbitrum, base],
ssr: true, // If your dApp uses server side rendering (SSR)
});
config가 설정되어 있다면 다음과 같이 rianbow wallet을 먼저 주입시켜 준 후에 app을 실행시킵니다.
const queryClient = new QueryClient();
const App = () => {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>
{/* Your App */}
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
);
};
만약 위의 템플릿 안에 해당 내용을 넣는다면 다음과 같이 넣을 수 있습니다.
적용하고자 하는 최상단 경로의 layout.tsx에 rainbow wallet의 설정 값을 넣어줍니다.
"use client";
import '@rainbow-me/rainbowkit/styles.css'; // ✅ RainbowKit 스타일 추가
import { Outfit } from "next/font/google";
import "./globals.css";
import AdminContent from "@/components/auth/AdminContent";
import WagmiWrapper from "@/components/web3/WagmiWrapper";
import { WagmiProvider, createConfig, http } from 'wagmi';
import { RainbowKitProvider } from '@rainbow-me/rainbowkit';
import { mainnet, arbitrum, arbitrumGoerli } from 'wagmi/chains';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const outfit = Outfit({
variable: "--font-outfit-sans",
subsets: ["latin"],
});
// ✅ QueryClient 인스턴스 생성
const queryClient = new QueryClient();
// ✅ Wagmi 설정 구성 (최신 방식)
const wagmiConfig = createConfig({
chains: [mainnet, arbitrum, arbitrumGoerli],
transports: {
[mainnet.id]: http(),
[arbitrum.id]: http(),
[arbitrumGoerli.id]: http(),
}
});
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${outfit.variable} dark:bg-gray-900`}>
<QueryClientProvider client={queryClient}>
<WagmiProvider config={wagmiConfig}>
<RainbowKitProvider>
<WagmiWrapper>
<AdminContent>
{children}
</AdminContent>
</WagmiWrapper>
</RainbowKitProvider>
</WagmiProvider>
</QueryClientProvider>
</body>
</html>
);
}
이런식으로 만든다면 화면 안에 지갑이 들어간 형태로 만들 수 있습니다.
그럼 지갑을 이용해서 서명을 하는 기능을 넣으려면 어떻게 해야 할까요?
여기서 서명을 하는 함수를 커스텀 hook으로 만든 후에 각 컴포넌트에서 해당 hook을 가져와서 사용하면 됩니다.
다음은 useSignature.ts 라는 자체적으로 제작한 hook입니다.
import { useAccount, useSignMessage } from 'wagmi';
export default function useSignature() {
const { address, isConnected } = useAccount();
const { signMessageAsync } = useSignMessage();
const signAndSendRequest = async () => {
if (!address || !isConnected) {
alert("지갑이 연결되지 않았습니다.");
return;
}
const message = `로그인을 위한 서명 요청: ${new Date().toISOString()}`;
console.log(message);
try {
const signature = await signMessageAsync({ message });
console.log("✅ 서명 성공:", signature);
} catch (error) {
console.error("❌ 서명 요청 오류:", error);
}
};
return {
signAndSendRequest
};
}
위의 설정대로 rainbow wallet에서는 wagmi를 내부적으로 사용하고 있습니다. 따라서 wagmi의 함수를 hook에서 사용할 수 있습니다.
다음과 같이 signAndRequest 훅을 만든다면 이 훅을 가져와서 각 컴포넌트에서 원할때마다 지갑의 서명을 진행할 수 있습니다.
"use client";
import React from "react";
import { useModal } from "../../hooks/useModal";
import { Modal } from "../ui/modal";
import Button from "../ui/button/Button";
import Input from "../form/input/InputField";
import Label from "../form/Label";
import useSignature from "@/hooks/useSignature"; // ✅ 훅 경로는 실제 위치에 맞게
export default function UserInfoCard() {
const { isOpen, openModal, closeModal } = useModal();
const { signAndSendRequest } = useSignature(); // ✅ 훅 호출해서 서명 함수 가져오기
const handleSave = () => {
// Handle save logic here
signAndSendRequest(); // ✅ 버튼 누르면 서명 시도
console.log("Saving changes...");
closeModal();
};
return (
보면 다음과 같이 hook경로를 통해서 useSignature라는 커스텀 훅을 가져와서 UserInfoCard라는 템플릿에 존재하는 Modal안에서 실행시킨 것을 볼 수 있습니다. 이렇게 된다면 Edit을 하기 전에 지갑주소에 대한 서명을 진행하고 save가 진행되게 됩니다.
'개발 > frontend' 카테고리의 다른 글
Next.js "Use client" 사용법 (1) | 2025.04.02 |
---|---|
Next.js Hydration 에러 처리 (Rainbow Wallet 사용 시 적용 필요) (0) | 2025.04.02 |
Metamask + Next.js 적용해서 프론트 페이지 만들어보기 (0) | 2024.06.13 |
텔레그램 봇 기본 틀 만들어 보기 (기본 템플릿, 깃허브 소스코드 및 사용방법 포함, javascript & typescript) (0) | 2023.07.29 |
React 시작해보기 - Tic Tac Toe 튜토리얼 프로젝트로 기초 다져보기 (0) | 2023.07.22 |