Next.jsでMetamaskを使用するDAppの優先ストレージ
DAOやDAPPなどのWeb3アプリケーションはますます人気が高まっています。 Web3の前提により、これらのプラットフォームは、ユーザーのIDを他のユーザーにプライベートに保ち、さらには自分自身に知られないようにしながら、ユーザーにより個人的でカスタマイズされたエクスペリエンスを提供することになっています。
このプロジェクトでは、このような場合のユーザーエクスペリエンスを向上させる方法を探ります。
多くのアプリケーションでは、ETHなどの暗号資産を管理するためにMetamaskのようなブロックチェーンウォレットが使用されます。このようなウォレットを使用すると、ユーザーはさまざまなチェーンでアカウントを作成できます。これらのアカウントは秘密鍵を使用して作成されますが、各アカウントにはそれらを表すパブリックアドレスがあります。
公開鍵は誰でも表示できますが、それに関連するトランザクションは所有者のみが管理できます。ウォレット接続は、そのようなアプリケーションに確実な認証メカニズムを提供します。
このプロジェクトでは、Next.jsを使用して設定ストレージシステムを実装します。このシステムでは、ユーザーが提供されるインターフェイスをカスタマイズします。つまり、そのサイトに戻るたびに、意図したとおりにUIが表示されます。
さらに強力なアイデアは、企業のサブプラットフォームとクロスプラットフォーム間でユーザーインターフェイスを正規化することです。このように、ユーザーが他のサイトで設定した設定をサポートする特定のサイトに移動するたびに、同様のエクスペリエンスが得られます。
また、このプロジェクトを変更して、カスタマイズ用のパラメーターの数を変更することもできます。これにより、思いついた構造にプロジェクトを成形できます。
このサンプルプロジェクトでは、パラメータは2つだけです。つまり:
- ウェブサイトのテーマ
- ユーザーの挨拶の名前
UpstashRedis環境変数を構成する
- Upstashで無料のRedisデータベースを作成する
- .env.local.exampleファイルを.env.localにコピーします(Gitでは無視されます):
- UPSTASH_REDIS_REST_URLおよびUPSTASH_REDIS_REST_TOKENは、Upstashコンソールのデータベース詳細ページにあります。
依存関係をインストールします:npm i @upstash/redis @metamask/detect-provider @mui/material @emotion/react @emotion/styled
api/store.js
を作成します ファイル
Redis SDKを構成し、ハンドラー関数をエクスポートします。
api / store.jsimport { Redis } from "@upstash/redis"
const redis = Redis.fromEnv()
export default async function handler(req, res) {
const accountID = await JSON.parse(req.body).accountID
const body = req.body
const setResult = await redis.set(accountID, body);
res.status(200).json({ result: setResult })
}
api/[accountAddress].js
を作成します ファイル
同様に、Redis SDKを構成し、ハンドラーをエクスポートします。
api / [accountAddress] .jsimport { Redis } from "@upstash/redis"
const redis = Redis.fromEnv()
export default async function handler(req, res) {
const accountID = req.query.accountAddress
const getResult = await redis.get(accountID)
res.status(200).json({ result: getResult })
}
index.js
を構成します ファイル
const [accountAddress, setAccountAddress] = useState(null)
const [themePreference, setThemePreference] = useState("light")
const [greetingMessage, setGreetingMessage] = useState("Anonymous Person")
const [userSettings, setUserSettings] = useState(null)
// Check if connection already established. If so, fetch the data.
useEffect(() => {
checkConnection()
getPreferences()
}, [accountAddress])
async function connect() {
const provider = await detectEthereumProvider()
console.log("provider:", provider)
if (provider) {
console.log('Ethereum successfully detected!')
provider.request({ method: "eth_requestAccounts" }).then((accounts) => {
if (!accountAddress) {
setAccountAddress(accounts[0])
}
}).catch((err) => console.log(err))
console.log("window.ethereum:", window.ethereum)
getPreferences()
} else {
alert('Please install MetaMask!')
}
}
async function checkConnection() {
const provider = await detectEthereumProvider()
if (provider) {
provider
.request({ method: 'eth_accounts' })
.then(accounts => {
setAccountAddress(accounts[0])
})
.catch(console.log)
} else {
console.log("Not connected, window.ethereum not found")
}
}
async function setPreferences(themePreference, greetingMessage) {
if (accountAddress) {
const res = await fetch(`/api/store`, {
method: "POST",
body: JSON.stringify({
accountID: accountAddress,
themePreference: themePreference,
greetingMessage: greetingMessage,
})
})
const data = await res.json()
}
else {
alert("No account address detected")
}
}
async function getPreferences(e) {
if (accountAddress) {
console.log("Fetching user preferences...")
const res = await fetch(`/api/${accountAddress}`, { method: "GET" })
const data = await res.json()
setUserSettings(data.result)
if (data.result) {
setThemePreference(data.result.themePreference)
setGreetingMessage(data.result.greetingMessage)
}
}
else {
console.log("No account connected yet!")
}
}
次の関数を入力フィールド/ボタンなどにバインドします。
async function handleDarkMode(e) {
console.log("themePreference:", themePreference)
const newPreference = themePreference == "light" ? "dark" : "light"
setThemePreference(newPreference)
await setPreferences(newPreference, greetingMessage)
await getPreferences()
}
async function takeGreetingMessage(e) {
// submit with enter/return key
if (e.keyCode == 13) {
const message = e.target.value
setGreetingMessage(message)
console.log(message)
await setPreferences(themePreference, message)
await getPreferences()
e.target.value = ""
}
}
関連するMaterial-UI依存関係をインポートしたことを確認してください。
return (
<div className={styles.container}>
<h2>Web3 Preferences Holder</h2>
<Button variant="contained" onClick={connect}>Connect Metamask</Button>
<p>
Lets you keep user preferences on cross-websites
</p>
<br />
<p>For example, take a greeter message from user.</p>
<TextField label="Call me..." variant="outlined" size="small" onKeyDown={takeGreetingMessage} />
<br />
<br />
<Button onClick={handleDarkMode} variant="contained" size="small" style={{ backgroundColor: "#3D3B3B" }} > Switch Dark Mode </Button>
<p>Sample Component/Page:</p>
<Showcase userSettings={userSettings} />
</div>
)
sampleComponent.jsx
を作成します ディレクトリ内のcomponents
これは、Webインターフェイス、アプリケーションなどを表す主要なコンポーネントです。このコンポーネントは、システムがどのように機能するかを視覚化し、主な目標が提供します。ここで、パラメータを好きなように解析し、サンプルインターフェイスを作成します。
この場合、プロジェクトは次のように構成されます。
import React from "react";
import { useState} from 'react'
import { ThemeProvider, createTheme } from '@mui/material/styles'
import { orange, grey } from '@mui/material/colors'
const lightTheme = createTheme({
palette: {
primary: {
main: grey[400],
},
}
})
const darkTheme = createTheme({
palette: {
primary: {
main: orange[400],
},
}
})
export default function Showcase(parameters) {
const userSettings = parameters.userSettings
const [theme, setTheme] = useState("light")
const [greetingMessage, setGreetingMessage] = useState("Anonymous Person")
const items = []
if (userSettings) {
const obj = userSettings[0]
for (const key in userSettings) {
items.push(<li key={key}> {key}: {userSettings[key]} </li>)
}
if (userSettings["themePreference"] != theme) {
setTheme(userSettings["themePreference"] == "light" ? "light" : "dark")
}
if (!greetingMessage || userSettings["greetingMessage"] != greetingMessage) {
if (userSettings["greetingMessage"]) {
setGreetingMessage(userSettings["greetingMessage"])
}
else {
setGreetingMessage("not the same message")
}
}
}
return (
<div>
<div style={{
padding: 10,
margin: 10,
backgroundColor: theme == "light" ? "grey" : "orange",
border: "solid",
borderWidth: "30px",
borderColor: theme == "light" ? "#B2B2B2" : "black"
}}>
<ThemeProvider
theme={theme == "light" ? lightTheme : darkTheme}
>
<h2>Hi, {greetingMessage}!</h2>
<p>User and their preferences:</p>
{items}
</ThemeProvider>
</div>
</div>
);
}
- ユーザーは、プラットフォームに挨拶したときに表示したい名前を入力します。
- ユーザーは、明るいテーマと暗いテーマのどちらかを選択します。
ユーザー設定が設定されます。今後は、提供されているプリファレンスインターフェイスをサポートする任意のプラットフォームで同じインターフェイスを表示できます。ユーザーがカスタマイズしたテンプレート。
このコンポーネントは、ユーザーが設定した設定をテキスト形式で表示します。好きなように解析できます。
この簡単な例でわかるように、ユーザーに表示するコンポーネントをパラメーター化できます。デザインを改善し、パラメーターの数を増やすことで、いつでもこのプロジェクトに追加できます。ただし、基本的なロジックは同じままです。
プロジェクトのデモを見るには、こちらを確認してください。
完成したプロジェクトを確認するには、プロジェクトのGithubリポジトリにアクセスしてください。
そこに、Vercel展開用のクイック展開ボタンが表示されます。プロジェクトを迅速にデプロイし、UpstashRedis統合を自動的に作成できます。
ご意見・ご感想をお待ちしております。ツイッターまたは不和で私たちに連絡することができます。
-
UpstashRedisを使用したNetlifyグラフのグローバルキャッシュ
昨日、NetlifyはNetlify Graphと呼ばれる新機能を発表しました。私の同僚は最近、写真の同様の欠落部分を強調し、Netlifyは解決に向けて良い一歩を踏み出しました。 基本的に、Netlify Graphは、開発者がWebアプリのGraphQL API呼び出しを構築するのに役立ちます。NetlifyDashboardでGraphQLリクエストを準備した後、シングルクリックでクライアントコードをプロジェクトに挿入できます。 Netlify関数をサードパーティサービスと一緒に使用することには欠点があります。クライアント側のリクエストは、最初にNetlifyバックエンド(関数)に送
-
Next.jsに最適なデータベース
Next.jsを使用すると、開発者はサーバー側レンダリング機能を備えたフルスタックアプリケーションを構築できます。 VercelとNetlifyは、サーバーレス関数を使用してバックエンドAPIを作成するのに役立ちます。次の質問は、Next.jsアプリの理想的なデータベースは何かということです。この投稿では、Next.jsコミュニティで人気のあるデータベースを確認します。それらがサーバーレスモデルにどのように適合するかについてコメントします。確認すべき2つのこと: サーバーレス価格設定:価格は従量制ですか?データベースが使用されていない場合でも、料金を支払う必要がありますか? サーバーレス接続