For the complete documentation index, see llms.txt. This page is also available as Markdown.

Web3 통합

이 페이지에서는 지갑 연결, 트랜잭션, 온체인 이벤트 처리를 포함하여 블록체인 기능을 Redux 및 RTK Query와 통합하는 패턴을 다룹니다.

핵심 원칙: Web3 객체는 Redux 밖에 두기

권장 아키텍처

Web3 컨텍스트 (Redux 밖)

// src/contexts/Web3Context.tsx
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
import { ethers } from 'ethers';

interface Web3ContextValue {
  provider: ethers.providers.Web3Provider | null;
  signer: ethers.Signer | null;
  account: string | null;
  chainId: number | null;
  connect: () => Promise<void>;
  disconnect: () => void;
}

const Web3Context = createContext<Web3ContextValue | undefined>(undefined);

export function Web3Provider({ children }: { children: ReactNode }) {
  const [provider, setProvider] = useState<ethers.providers.Web3Provider | null>(null);
  const [signer, setSigner] = useState<ethers.Signer | null>(null);
  const [account, setAccount] = useState<string | null>(null);
  const [chainId, setChainId] = useState<number | null>(null);

  const connect = async () => {
    if (!window.ethereum) {
      throw new Error('MetaMask가 설치되어 있지 않습니다');
    }

    const web3Provider = new ethers.providers.Web3Provider(window.ethereum);
    const accounts = await web3Provider.send('eth_requestAccounts', []);
    const network = await web3Provider.getNetwork();
    const signer = web3Provider.getSigner();

    setProvider(web3Provider);
    setSigner(signer);
    setAccount(accounts[0]);
    setChainId(network.chainId);
  };

  const disconnect = () => {
    setProvider(null);
    setSigner(null);
    setAccount(null);
    setChainId(null);
  };

  // 계정 변경을 감지
  useEffect(() => {
    if (!window.ethereum) return;

    const handleAccountsChanged = (accounts: string[]) => {
      if (accounts.length === 0) {
        disconnect();
      } else {
        setAccount(accounts[0]);
      }
    };

    const handleChainChanged = (chainIdHex: string) => {
      const newChainId = parseInt(chainIdHex, 16);
      setChainId(newChainId);
    };

    window.ethereum.on('accountsChanged', handleAccountsChanged);
    window.ethereum.on('chainChanged', handleChainChanged);

    return () => {
      window.ethereum?.removeListener('accountsChanged', handleAccountsChanged);
      window.ethereum?.removeListener('chainChanged', handleChainChanged);
    };
  }, []);

  return (
    <Web3Context.Provider
      value={{ provider, signer, account, chainId, connect, disconnect }}
    >
      {children}
    </Web3Context.Provider>
  );
}

export function useWeb3() {
  const context = useContext(Web3Context);
  if (!context) {
    throw new Error('useWeb3는 Web3Provider 내부에서 사용해야 합니다');
  }
  return context;
}

Web3 상태를 위한 Redux Slice

Redux에는 직렬화 가능한 Web3 상태만 저장하세요:

컨텍스트와 Redux 동기화

Web3 컨텍스트를 Redux에 연결하세요:

트랜잭션 생명주기

트랜잭션 전송

컴포넌트에서 사용하기

온체인 이벤트 수신

Web3 데이터와 RTK Query

블록체인 데이터를 사용하는 엔드포인트를 만드세요:

캐시 무효화 전략

네트워크 변경 시

계정 변경 시

트랜잭션 확인 후

모범 사례

1. 관심사 분리

2. 트랜잭션 상태 처리

3. 롤백이 있는 낙관적 업데이트

4. 이벤트 리스너 정리

다음 단계

마지막 업데이트