I have created a dApp which uses a context folder to communicate with the smart contract, in the context a function called loadAuth
which checks if the user is authenticated, then set the account
state to user.wallet.address
.
context/DataContext.tsx
'use client'
declare let window: any;
import { createContext, useContext, useState } from "react";
import Web3 from "web3";
import { usePrivy } from "@privy-io/react-auth";
interface DataContextProps {
account: string;
loading: boolean;
loadAuth: () => Promise<void>;
};
const DataContext = createContext<DataContextProps>({
account: "",
loading: true,
loadAuth: async () => {},
});
interface Props {
children?: React.ReactNode;
};
export const DataProvider: React.FC<Props> = ({ children }) => {
const data = useProviderData();
return <DataContext.Provider value={data}>{children}</DataContext.Provider>;
};
export const useData = () => useContext<DataContextProps>(DataContext);
export const useProviderData = () => {
const [loading, setLoading] = useState(true);
const [account, setAccount] = useState("");
const {ready, authenticated, user} = usePrivy();
const loadAuth = async () => {
if (ready && authenticated && user) {
const userWallet = user.wallet ? user.wallet.address : "";
console.log('walletAddress: ', userWallet);
setAccount(userWallet);
}
};
return {
account,
loading,
loadAuth,
};
};
The Navbar login users, and upon completion, calls loadAuth to set the account
state. The account
state is used to check if the user has an address, and then display it.
import { useRouter } from "next/navigation";
import React from "react";
import { useData } from "../contexts/DataContext";
import { useLogin } from "@privy-io/react-auth";
function Navbar() {
const router = useRouter();
const { account, loadAuth } = useData();
const {login} = useLogin({
onComplete(user, isNewUser, wasAlreadyAuthenticated, loginMethod, loginAccount) {
loadAuth();
router.push("/");
},
})
return (
<>
<nav className="w-full h-16 mt-auto max-w-5xl">
<div className="flex flex-row justify-between items-center h-full">
{account ? (
<div className="bg-green-500 px-6 py-2 rounded-md cursor-pointer">
<span className="text-lg text-white">
{account.substring(0, 10)}...
</span>
</div>
) : (
<div
className="bg-green-500 px-6 py-2 rounded-md cursor-pointer"
onClick={login}
>
<span className="text-lg text-white">Connect</span>
</div>
)}
</div>
</nav>
</>
);
}
export default Navbar;
The issue is loadAuth
does not get called properly, and account
state never gets assigned the user.wallet.address
Update: app/layout.tsx
import type { Metadata } from "next";
import PrivyProviderWrapper from "../components/privy-provider-wrapper";
import "./globals.css";
export const metadata: Metadata = {
title: "Create Next App",
description: "Create Next App",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>
<PrivyProviderWrapper>
{children}
</PrivyProviderWrapper>
</body>
</html>
);
}
You are not using DataProvider
in your providers tree that's why your loadAuth
function is not doing anything.
Update your layout as follow to use DataProvider
.
src/context/DataContext.tsx
'use client'
declare let window: any;
import { createContext, useContext, useState } from "react";
import Web3 from "web3";
import { usePrivy } from "@privy-io/react-auth";
interface DataContextProps {
account: string;
loading: boolean;
loadAuth: () => Promise<void>;
};
const DataContext = createContext<DataContextProps>({
account: "",
loading: true,
loadAuth: async () => {},
});
interface Props {
children?: React.ReactNode;
};
export const DataProvider: React.FC<Props> = ({ children }) => {
const data = useProviderData();
return <DataContext.Provider value={data}>{children}</DataContext.Provider>;
};
export const useData = () => useContext<DataContextProps>(DataContext);
export const useProviderData = () => {
const [loading, setLoading] = useState(true);
const [account, setAccount] = useState("");
const {ready, authenticated, user} = usePrivy();
const loadAuth = async () => {
if (ready && authenticated && user) {
const userWallet = user.wallet ? user.wallet.address : "";
console.log('walletAddress: ', userWallet);
setAccount(userWallet);
}
};
return {
account,
loading,
loadAuth,
};
};
src/app/layout.tsx
import type { Metadata } from "next";
import PrivyProviderWrapper from "../components/privy-provider-wrapper";
import "./globals.css";
// adjust the path according to your folders layout.
++ import { DataProvider } from "@/src/src/context/DataContext"
export const metadata: Metadata = {
title: "Create Next App",
description: "Create Next App",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>
<PrivyProviderWrapper>
++ <DataProvider>
{children}
++ </DataProvider>
</PrivyProviderWrapper>
</body>
</html>
);
}