notion-sdk-js icon indicating copy to clipboard operation
notion-sdk-js copied to clipboard

notionhq/client and Next.js 13.4.9 with server action

Open jercomio opened this issue 2 years ago • 4 comments
trafficstars

I'm using notionhq/client with Next.js 13.4.9 and TypeScript for an App project and I have the following issue :

This is the function to get database : export async function getDatabase(databaseId: string) { try { const response = await notion.databases.query({ database_id: databaseId! }) return response } catch (error: unknown) { if (isNotionClientError(error)) { switch (error.code) { case ClientErrorCode.RequestTimeout: console.log(RequestTimeout error: ${error.code}); break case APIErrorCode.ObjectNotFound: console.log(ObjectNotFound error: ${error.code}); break case APIErrorCode.Unauthorized: console.log(Unauthorized error: ${error.code}); break default: console.log(Default error: ${error.code}); break } } } }

Then, this is a function using a server action : async function getData() { 'use server' const data = await getDatabase(databaseId!) return data }

And I call a client component like that : <Component data={getData()} />

Now, in my component if I write console.log(data), here the response I have :

Chunk { reason: null, status: "resolved_model", value: "{...}", _response: {•••} }

To get a good response and use it, I have to write this in useEffect for example : console.log(JSON.parse(data.value)

And now I have my array of object from Notion database and I can use it.

jercomio avatar Jul 17 '23 17:07 jercomio

First of all, please provide an issue in a readable syntax. You can write codes in ```ts <code> ``` format and your codes will be much readable.

Since your getData is an async function, therefore you need to await to retrieve data otherwise it will return a Promise.

await getData()

Note that in order to use await, the Page Component needs to be async.

// page.tsx

export default async function Home() {
  // ...

Simple example:

// page.tsx
import { Client } from '@notionhq/client'

const notion = new Client({
  auth: process.env.NOTION_TOKEN
})

export default async function Home() {
  async function getData() {
    'use server'
    return await notion.databases.query({
      database_id: process.env.NOTION_DATABASE_ID as string,
    })
  }
  const data = await getData()

  return (<Component data={data} />)
}

devjiwonchoi avatar Aug 16 '23 13:08 devjiwonchoi

Yes, Thanks ! I updated my code and I get a right result now 👍

// page.tsx

export default async function Home() {

  async function getData() {
    'use server'
    return await getDatabase(databaseId!)
  }
  const data = await getData()

  async function getPageContent() {
    'use server'
    return await getPage(pageId!)
  }
  const page = await getPageContent()

  async function getBlocksIntoPage() {
    'use server'
    const blocks = await getBlocks(pageId!)
    const childBlocks = await Promise.all(
      blocks!
        .filter((block) => (block as any).has_children)
        .map(async (block) => {
          return {
            id: block.id,
            children: await getBlocks(block.id)
          }
        })
    )
    const blocksWithChildren = blocks?.map((block) => {
      if ((block as any).has_children && !(block as any)[(block as any).type].children) {
        (block as any)[(block as any).type]["children"] = childBlocks.find(
          (x) => x.id === block.id
        )?.children
      }
      return block
    })
    return blocksWithChildren
  }
  const blocks = await getBlocksIntoPage()


  return (
    <main>
      <HomePage 
        data={data} 
        page={page} 
        blocks={blocks} 
      />
    </main>
  )
}

With .has_children, the type of block (PartialBlockObjectResponse | BlockObjectResponse) is not valid. I have to write (block as any).has_children. I don't understand why ?

jercomio avatar Aug 18 '23 13:08 jercomio

I've noticed some type issues in notion client also. I'm planning to open an issue for this soon.

Since has_children is in type BlockObjectResponse but not PartialBlockObjectResponse, you cannot directly access block.has_children.

For now, just pass any to block.

Example:

blocks.map((block: any) => block.has_children)

devjiwonchoi avatar Aug 18 '23 14:08 devjiwonchoi

Ok, thanks ! 👍

jercomio avatar Aug 18 '23 14:08 jercomio