I have dynamic links like so localhost:3000/[username]. I query against a mongodb. If a username FooBar
existed in the database then it would resolve; otherwise, it would say User {slug} Not Found.
I was able to verify my graphQL query is working fine. Requesting Foobar with getUser() returns a user object with a username string set to Foobar. Invalid users return as null. I am confident this isnt the issue. I believe the problem is incorrectly using an asynchronous method in UseEffect. I have console.log(fetchData)
set which never logs in my console indicating to me the fetchData()
method is never called. Here is A Guide I tried to follow to avoid this issue.
Here is my code:
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { getUser } from '@/lib/users';
import {subscribe} from "graphql";
const UserPage = () => {
const router = useRouter();
const { slug } = router.query;
const [isValidUser, setIsValidUser] = useState(false);
useEffect(() => {
const fetchData = async () => {
console.log(fetchData)
let result;
if (slug === undefined || slug == null) {
result = null;
} else {
result = Array.isArray(slug) ? slug[0] : slug;
const user = await getUser(result);
if (user) {
setIsValidUser(true);
}
}
return result;
}
if (slug) {
fetchData().catch(console.error);
}
}, [slug]);
return (
<>
{isValidUser ? (
<p>User {slug} found!</p>
) : (
<p>User {slug} not found.</p>
)}
</>
);
};
export default UserPage;
Some side notes: I am using NextJS, mongoDb and NextAuth to authenticate user agaisnt a database.
Edit: For good measure here is the gql query:
import { apolloClient } from "@/pages/_app";
import { GET_USER_BY_USERNAME_OR_ADDRESS } from "../db/queries/userQueries";
import { ADD_USER } from "../db/mutations/userMutations";
const GET_USER_BY_USERNAME_OR_ADDRESS = gql`
query GetUserByUsernameOrAddress($usernameOrAddress: String) {
getUserByUsernameOrAddress(usernameOrAddress: $usernameOrAddress) {
address
bio
username
}
}
`;
const getUser = async (addressOrUsername: string) => {
try {
const { data } = await apolloClient.query({
query: GET_USER_BY_USERNAME_OR_ADDRESS,
variables: { addressOrUsername },
});
if ( data ){
return data;
} else {
return null;
}
} catch (error) {
console.error(error);
}
return false;
};
I found out that NextJS can process the slug using GetServerSideProps. I can then pass it into my page as a prop like so. Doing this allowed me to first fetch the asynchronous process on the serverside then pass it to the front end for nextJS to render.
import { GetServerSideProps } from 'next'
import { getUser } from '@/lib/users';
import ProfilePage from "./profile";
interface Props {
isValidUser: boolean;
slug: string | null;
address: string;
}
const UserPage = ({ isValidUser, address, slug }: Props) => {
return (
<>
{isValidUser && address? (
<>
<ProfilePage address={address}/>
</>
) : (
<p>User {slug} not found.</p>
)}
</>
);
};
export const getServerSideProps: GetServerSideProps = async (context) => {
const slug = context.params?.address as string;
let isValidUser = false;
let address = "";
if (slug) {
try {
const user = await getUser(slug);
if (user.getUserByUsernameOrAddress != null) {
address = user.getUserByUsernameOrAddress.address;
isValidUser = Boolean(user);
}
} catch (error) {
console.error(error);
}
}
return {
props: {
isValidUser,
address,
slug: slug || null
}
};
}
export default UserPage;