webサイトにウォレット連携ボタンを実装しよう
🛍 ウォレットに接続するボタンをレンダリングする
WebアプリケーションからPhantom Walletにアプリケーションへの接続を促すため、connectWallet
ボタンを作成する必要があります。
web3の世界では、ウォレット接続ボタンは「サインアップ/ログイン」ボタンの役割を果たします。
pages/index.tsx
ファイルを下記の通り変更してください。
// index.tsx
import Head from "next/head";
import Image from "next/image";
import { useEffect } from "react";
import twitterLogo from "@/twitter-logo.svg";
import styles from "@/styles/Home.module.css";
// 定数の宣言
const TWITTER_HANDLE = "あなたのTwitterハンドル";
const TWITTER_LINK = `https://twitter.com/${TWITTER_HANDLE}`;
const Home = () => {
const checkIfWalletIsConnected = async () => {
try {
const { solana } = window;
if (solana && solana.isPhantom) {
console.log("Phantom wallet found!");
const response = await solana.connect({ onlyIfTrusted: true });
console.log(
"Connected with Public Key:",
response.publicKey.toString()
);
} else {
alert("Solana object not found! Get a Phantom Wallet 👻");
}
} catch (error) {
console.error(error);
}
};
/*
* コードが壊れないように、下記関数を定義しましょう。
* 下記はその関数の実装です。
*/
const connectWallet = async () => {};
/*
* ユーザーがまだウォレットをアプリに接続していないときに
* このUIを表示します。
*/
const renderNotConnectedContainer = () => (
<button
className={`${styles.ctaButton} ${styles.connectWalletButton}`}
onClick={connectWallet}
>
Connect to Wallet
</button>
);
useEffect(() => {
const onLoad = async () => {
await checkIfWalletIsConnected();
};
onLoad();
}, []);
return (
<>
<Head>
<title>Candy Drop</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<div className={styles.container}>
<div>
<p className={styles.header}>🍭 Candy Drop</p>
<p className={styles.subText}>NFT drop machine with fair mint</p>
{/* ウォレットに接続するボタンをここでレンダリングします */}
{renderNotConnectedContainer()}
</div>
<div className={styles.footerContainer}>
<Image
alt="Twitter Logo"
className={styles.twitterLogo}
src={twitterLogo}
/>
<a
className={styles.footerText}
href={TWITTER_LINK}
target="_blank"
rel="noreferrer"
>{`built on @${TWITTER_HANDLE}`}</a>
</div>
</div>
</main>
</>
);
};
export default Home;
これで、Webアプリケーションに「ウォレットに接続」というグラデーションボタンが表示されます。
ユーザーがウォレットを Web アプリケーションに接続していない場合にのみ、Connect to Wallet
ボタンが表示されます。
そこで、このウォレットのデータをReactのstateに格納してみてましょう。そうすればボタンを表示するかどうかを判断するフラグとしても使えます。
pages/index.tsx
を修正します。
まずは下記のようにuseState
をコンポーネントにインポートする必要があります。
// index.tsx
import { useEffect, useState } from "react";
次に、 checkIfWalletIsConnected
関数のすぐ上に進み、下記のstate
の宣言を追加します。
// index.tsx
// State
const [walletAddress, setWalletAddress] = useState(null);
state
を保持する準備ができたので、ここでいくつかコードを更新しましょう。
index.tsx
を下記の通り修正してください。
// index.tsx
import Head from "next/head";
import Image from "next/image";
import { useEffect, useState } from "react";
import twitterLogo from "@/twitter-logo.svg";
import styles from "@/styles/Home.module.css";
// Constants
const TWITTER_HANDLE = "あなたのTwitterハンドル";
const TWITTER_LINK = `https://twitter.com/${TWITTER_HANDLE}`;
const Home = () => {
// State
const [walletAddress, setWalletAddress] = useState(null);
// Actions
const checkIfWalletIsConnected = async () => {
try {
const { solana } = window;
if (solana && solana.isPhantom) {
console.log("Phantom wallet found!");
const response = await solana.connect({ onlyIfTrusted: true });
console.log(
"Connected with Public Key:",
response.publicKey.toString()
);
/*
* ユーザーの公開鍵を後から使える状態にします。
*/
setWalletAddress(response.publicKey.toString());
} else {
alert("Solana object not found! Get a Phantom Wallet 👻");
}
} catch (error) {
console.error(error);
}
};
const connectWallet = async () => {};
const renderNotConnectedContainer = () => (
<button
className={`${styles.ctaButton} ${styles.connectWalletButton}`}
onClick={connectWallet}
>
Connect to Wallet
</button>
);
useEffect(() => {
const onLoad = async () => {
await checkIfWalletIsConnected();
};
onLoad();
}, []);
return (
<>
<Head>
<title>Candy Drop</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<div className={styles.container}>
<div>
<p className={styles.header}>🍭 Candy Drop</p>
<p className={styles.subText}>NFT drop machine with fair mint</p>
{/* ウォレットアドレスを持っていない場合にのみ表示する条件を追加する */}
{!walletAddress && renderNotConnectedContainer()}
</div>
<div className={styles.footerContainer}>
<Image
alt="Twitter Logo"
className={styles.twitterLogo}
src={twitterLogo}
/>
<a
className={styles.footerText}
href={TWITTER_LINK}
target="_blank"
rel="noreferrer"
>{`built on @${TWITTER_HANDLE}`}</a>
</div>
</div>
</main>
</>
);
};
export default Home;
簡単に修正点を確認しましょう。
// index.tsx
const checkIfWalletIsConnected = async () => {
try {
const { solana } = window;
if (solana && solana.isPhantom) {
console.log("Phantom wallet found!");
const response = await solana.connect({ onlyIfTrusted: true });
console.log("Connected with Public Key:", response.publicKey.toString());
/*
* ユーザーの公開鍵を後から使える状態にします。
*/
setWalletAddress(response.publicKey.toString());
} else {
alert("Solana object not found! Get a Phantom Wallet 👻");
}
} catch (error) {
console.error(error);
}
};
ファントムウォレットを接続するとユーザーのウォレットからデータを受信しました。
これで、後で使用できるように状態に保存してみましょう。
// index.tsx
{
/* ウォレットアドレスを持っていない場合にのみ表示する条件を追加する */
}
{
!walletAddress && renderNotConnectedContainer();
}
ここでは state