K
Kinde3mo ago
zhefciad

Manually fetch user

nextjs sdk: Is it possible to fetch the user inside a function? Because on component mount, it's null. Then after some time, it loads. I want to track the progress with a loading state like the other fetches in fetchData. How do I do that? It's running the useEffect twice which messes up the loading state.
const ListingContent: React.FC<ListingCardModalProps> = ({ listing }) => {
const [loading, setLoading] = useState(false);
const { user } = useKindeBrowserClient(); //I want this to get fetched inside fetchData so that its progress gets tracked too.
...
useEffect(() => {
const fetchData = async () => {
setLoading(true);
// get kinde user in database
const kindeUserUrl = `${baseUrl}/api/kinde-users?filters[kindeID][$eq]=${user?.id}`;
const [kindeUserResponse] = await Promise.all([fetch(kindeUserUrl)]);

const kindeUserData = await kindeUserResponse.json();

setKindeUser(kindeUserData.data[0]);

const sellerUrl = `${baseUrl}/api/kinde-users?filters[kindeID][$eq]=${listing.attributes.createdby_kindeID}`;
const sellerResponse = await fetch(sellerUrl);

const sellerData = await sellerResponse.json();

setSeller(sellerData.data[0].attributes);
await setLoading(false);
};

fetchData();
}, [user]);
...
const ListingContent: React.FC<ListingCardModalProps> = ({ listing }) => {
const [loading, setLoading] = useState(false);
const { user } = useKindeBrowserClient(); //I want this to get fetched inside fetchData so that its progress gets tracked too.
...
useEffect(() => {
const fetchData = async () => {
setLoading(true);
// get kinde user in database
const kindeUserUrl = `${baseUrl}/api/kinde-users?filters[kindeID][$eq]=${user?.id}`;
const [kindeUserResponse] = await Promise.all([fetch(kindeUserUrl)]);

const kindeUserData = await kindeUserResponse.json();

setKindeUser(kindeUserData.data[0]);

const sellerUrl = `${baseUrl}/api/kinde-users?filters[kindeID][$eq]=${listing.attributes.createdby_kindeID}`;
const sellerResponse = await fetch(sellerUrl);

const sellerData = await sellerResponse.json();

setSeller(sellerData.data[0].attributes);
await setLoading(false);
};

fetchData();
}, [user]);
...
3 Replies
Oli - Kinde
Oli - Kinde3mo ago
Hey @zhefciad, To fetch the user inside a function and track the loading state, you can utilize the getKindeServerSession helper function provided by Kinde in your Next.js API route. This allows you to fetch user data on the server side and then call this API endpoint from your component to manage the loading state effectively. Here's how you can do it: 1. Create an API route in your Next.js project that returns the user data from getKindeServerSession. This step is crucial as it allows you to fetch user data on the server side, which you can then call from your component.
// Example: /pages/api/user.js
import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";

export default async function handler(req, res) {
const { getUser } = getKindeServerSession(req, res);
const user = await getUser();
res.status(200).json({ user });
}

// Example: /pages/api/user.js
import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";

export default async function handler(req, res) {
const { getUser } = getKindeServerSession(req, res);
const user = await getUser();
res.status(200).json({ user });
}

2. Modify your component to fetch this API route. This way, you can manage the loading state just like you do with other fetches in fetchData.
useEffect(() => {
const fetchData = async () => {
setLoading(true);

// Fetch the Kinde user from your API route
const res = await fetch('/api/user');
const { user } = await res.json();

// Now you have the user, proceed with your other fetches
const kindeUserUrl = `${baseUrl}/api/kinde-users?filters[kindeID][$eq]=${user?.id}`;
const [kindeUserResponse] = await Promise.all([fetch(kindeUserUrl)]);
const kindeUserData = await kindeUserResponse.json();
setKindeUser(kindeUserData.data[0]);

const sellerUrl = `${baseUrl}/api/kinde-users?filters[kindeID][$eq]=${listing.attributes.createdby_kindeID}`;
const sellerResponse = await fetch(sellerUrl);
const sellerData = await sellerResponse.json();
setSeller(sellerData.data[0].attributes);

setLoading(false);
};

fetchData();
}, []);

useEffect(() => {
const fetchData = async () => {
setLoading(true);

// Fetch the Kinde user from your API route
const res = await fetch('/api/user');
const { user } = await res.json();

// Now you have the user, proceed with your other fetches
const kindeUserUrl = `${baseUrl}/api/kinde-users?filters[kindeID][$eq]=${user?.id}`;
const [kindeUserResponse] = await Promise.all([fetch(kindeUserUrl)]);
const kindeUserData = await kindeUserResponse.json();
setKindeUser(kindeUserData.data[0]);

const sellerUrl = `${baseUrl}/api/kinde-users?filters[kindeID][$eq]=${listing.attributes.createdby_kindeID}`;
const sellerResponse = await fetch(sellerUrl);
const sellerData = await sellerResponse.json();
setSeller(sellerData.data[0].attributes);

setLoading(false);
};

fetchData();
}, []);

By fetching the user data through an API route, you encapsulate the user fetching logic on the server side, which allows you to manage the loading state in your component effectively. This approach also avoids the issue of the useEffect hook running twice due to the user dependency, as the user fetching is now part of the initial data fetching logic.
zhefciad
zhefciad3mo ago
Thanks! Exactly what I needed.
Oli - Kinde
Oli - Kinde3mo ago
No worries