1

I am using useSWR in nextjs, the API endpoint is calling the database async query in api route.

  const fetcher = (url: string) => axios.get(url).then((r) => r.data);

  const { data, error } = useSWR("/api/model?data=" + selectedMatch, fetcher, {
    refreshInterval: 1000,
  });

Then console.log(data) afterward, the object does log:

console.log(data)
console.log(typeof(data))

Logged

However when I add console.log(Object.keys(data)) after these two lines of code, this error suddenly come out, and the typeof(data) become undefined.

I tried to change useSWR to useSWRImmutable, because I think useSWR might keep changing data while I try to fetch, but it doesn't work.

Cannot convert undefined or null to object

The endpoint that refers to the database query is something like this:

export const GET = async (req: NextRequest) => {
  await connectToDB();
  const matchString: String = req.nextUrl.searchParams.get("data");
  const events: any = {}; 
  const promises = matchString.split(",").map(async (match: string) => {
    try {
      events[match] = await Events.find({ name: match }).then((res) => res[0]);
    } catch (error) {
      events[match] = error;
      console.log("model/route.js error")
    }
  })

  await Promise.all(promises)
  return new Response(JSON.stringify(events), { status: 200 });
};

May I ask why and where's the problem?

Ahmed Sbai
  • 10,695
  • 9
  • 19
  • 38
TungTung
  • 163
  • 7
  • Does the console output data being undefined? When the endpoint is being fetched, data will be undefined, so before doing anything with data, check that it is defined. – eten Jul 19 '23 at 07:11
  • You mean when I do `Object.keys((data))`, the data is being fetched, so how should I check it is defined before log/use it successfully in this case? @eten – TungTung Jul 19 '23 at 07:19
  • `.map` is a _synchronous_ operation and you _really should not_ pass in _asynchronous_ functions into it - that will never work reliably. – David Jul 19 '23 at 07:43
  • so I should use for loop and `Promise.all` instead? @David – TungTung Jul 19 '23 at 07:45
  • No, you should have an asynchronous function and process the `matchString` _inside_ it @TungTung :) – David Jul 19 '23 at 07:45
  • Actually, I have an asynchronous function(added more detail to the code of database) and process the `matchString`, but I am using `.map` with async function, how should I correct it? @David – TungTung Jul 19 '23 at 07:49
  • Actually I copied to some examples online, not sure if there is better way to do it: https://stackoverflow.com/questions/40140149/use-async-await-with-array-map – TungTung Jul 19 '23 at 08:01
  • I got `error TypeError: Cannot read properties of undefined (reading 'headers') at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:261:61) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)` at your answer(will delete this comment later). – TungTung Jul 19 '23 at 08:14

1 Answers1

1

data returned by useSWR may not be stable over time, therefore it is always recommanded to execute such logic in a side effect and not from your component body, you want to make sure the code only runs when data is defined.

This should work as expected:

useEffect(() => {
 if(data){
  // move your logic here
 }
},[data])
Ahmed Sbai
  • 10,695
  • 9
  • 19
  • 38