Metamask에서 계정 및 체인 네트워크 전환 감지하는 방법

taeheeyoon·2022년 8월 11일
4

Trouble Shooting

목록 보기
3/3
post-thumbnail

시작하며

Metamask를 연결하여 NFT MarketPlace를 구현하던 중 예기치 못한 오류가 발생했습니다.
공식 문서를 보면서 계정 및 체인 네트워크 전환이 될 때 함수를 실행하는 로직을 구현했는데 계속 callback 중첩되어 발생하는 이슈였습니다. 이 글에서는 이 이슈를 해결했던 방법을 알아보겠습니다.

먼저 공식 문서에서 제공하는 자료를 확인해보겠습니다.

메타마스크 계정 전환 감지 (accountsChanged)

ethereum.on('accountsChanged', handler: (accounts: Array<string>) => void);

동작 원리는 이렇습니다.
eth_accountsRPC 메서드의 리턴 값이 변경될 때마다 MetaMask에서 이를 감지하고 있다가 변경 된 값을 리턴합니다. 즉, accountsChanged 사용자의 계정 주소가 변경될 때마다 리턴됨을 의미합니다.

네.. 끝입니다.
사실 이는 Event Listener와 같습니다. 그래서 사실 위에있는 코드만 작성하고 react 에서 확인하게되면 계정이 변경될 때(리렌더링 될 때)마다 Event Listener가 쌓이게 됩니다.

그럼 어떻게 될까요?
처음에는 한 번 callback 을 실행 시켰던 로직이 계정 변경을 여러번 하면 할 수록 callback을 중첩해서 실행하게 됩니다. (Event Listener는 같은 노드에 대해 중첩이 가능합니다)

계정이 변경될 때 단 한 번만 callback을 실행되는 것을 예상한 로직이 여러번 반복되는 것은 의도한 로직이 아닙니다.

따라서 저는 아래와 같이 코드를 작성하여 해결했습니다.

  const handleAccountChange = (...args) => {
    const account = args[0][0];
    if (!account) {
      
    } else if (account !== currentAccount) {
      //변경된 계정이 현재 계정과 다름
      //즉, 계정 변경 완료
    }
  };

  useEffect(() => {
    window.ethereum?.on('accountsChanged', handleAccountChange);
    return () => {
      window.ethereum?.removeListener('accountsChanged', handleAccountChange);
    };
  });

useEffect를 사용하여 컴포넌트가 마운트 됐을 때 (처음 나타났을 때) Event Listener를 등록하고 언마운트 됐을 때 (사라질 때) 등록한 Event Listener를 삭제해주었습니다.

Event Listener가 중첩되지 않아 의도하지 않던 Side Effect를 해결하였습니다.

마찬가지로 체인 네트워크 변경 로직도 살펴보겠습니다.

메타마스크 체인 네트워크 전환 감지 (networkChanged)

먼저 공식 문서에서 제공해주는 문법을 살펴보겠습니다.

ethereum.on('chainChanged', handler: (chainId: string) => void);

MetaMask는 현재 연결된 체인이 변경될 때 이 이벤트를 리턴합니다.

위와 같은 이유로 아래와 같이 코드를 작성하였습니다.

  const handleNetworkChanged = (...args) => {
    const networkId = args[0];
    window.location.reload();
  };

  useEffect(() => {
    window.ethereum?.on('networkChanged', handleNetworkChanged);
    return () => {
      window.ethereum?.removeListener('networkChanged', handleNetworkChanged);
    };
  });

한 가지 다른 점은 체인 네트워크 변경 시 window.location.reload()를 이용하여 페이지를 다시 로드하는 것을 권장하고있습니다. 왜냐하면 모든 RPC 요청은 현재 연결된 체인 네트워크에 요청됩니다. 따라서 현재 체인 ID를 추적하는 것이 중요하기 때문입니다.

profile
생각하는 대로 살지 않으면, 사는 대로 생각하게 된다.

0개의 댓글