Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use doesn't work in async Server Component #44778

Open
1 task done
amannn opened this issue Jan 11, 2023 · 3 comments
Open
1 task done

use doesn't work in async Server Component #44778

amannn opened this issue Jan 11, 2023 · 3 comments
Labels
bug Issue was opened via the bug report template.

Comments

@amannn
Copy link
Contributor

amannn commented Jan 11, 2023

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

    Operating System:
      Platform: darwin
      Arch: x64
      Version: Darwin Kernel Version 22.2.0: Fri Nov 11 02:08:47 PST 2022; root:xnu-8792.61.2~4/RELEASE_X86_64
    Binaries:
      Node: 16.16.0
      npm: 8.11.0
      Yarn: 1.22.18
      pnpm: 7.1.7
    Relevant packages:
      next: 13.1.2-canary.4
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true)

Link to the code that reproduces this issue

https://github.com/amannn/nextjs-bug-use-server

To Reproduce

  1. Clone the repro
  2. Run npm run dev
  3. Access http://localhost:3000

Describe the Bug

If I make use of use in an async component, this throws:

Screenshot 2023-01-11 at 16 56 03

Expected Behavior

I understand that in an async component you'd typically use async/await. However for reusable library code that can be executed either on the server or the client side, it would be very helpful if use can be called in server code as well.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

@amannn amannn added the bug Issue was opened via the bug report template. label Jan 11, 2023
@Fredkiss3
Copy link
Contributor

First thing, i don't think async server components work directly with use, since use can already load async functions and use replaces the await directive.

Secondly in your code you return directly the use, which i don't think is a good pattern ?
You could do this for ex :

import {use} from 'react';

export default function Index() {
  const status = use(
    fetch('https://dog.ceo/api/breeds/image/random').then(
      (response) => response.status
    )
  );
 return status;
}

And if you have multiple async operations, just call use multiple times :

import {use} from 'react';

export default function Index() {
  const status = use(
    fetch('https://dog.ceo/api/breeds/image/random').then(
      (response) => response.status
    )
  );

 const result2 = use(async () => { /*... do something async here */ });

 return status;
}

@amannn
Copy link
Contributor Author

amannn commented Jan 12, 2023

Hey, thanks for your reply!

First thing, i don't think async server components work directly with use, since use can already load async functions and use replaces the await directive.

As mentioned in my issue I understand that in an async component you'd typically use async/await. However for reusable library code that can be executed either on the server or the client side, it would be very helpful if use can be called in server code as well.

Secondly in your code you return directly the use, which i don't think is a good pattern ?

That doesn't make a difference.

@dbk91
Copy link

dbk91 commented Jan 20, 2023

I believe what @Fredkiss3 was pointing out is that use and async/await are simply paradigms to resolve promises in clients and servers respectively.

In your case, your shared library code would actually be the fetch call itself, exclusive of the keywords used to handle promises. To make this example clearer, extract the fetch call to a separate invokable function which returns a promise.

// api.js
export function getApiStatus() {
  return fetch('https://dog.ceo/api/breeds/image/random').then(
    (response) => response.status
  )
} 

Now you can easily share that code between the client and server using a pattern similar to the examples below.

// Client component
'use client';

import { use } from 'react';
import { getApiStatus } from 'api.js'

function MyClientComponent() {
  const responseStatus = use(getApiStatus())

  return <div>API Status: {responseStatus}</div>
}
// Server component

import { getApiStatus } from 'api.js'

async function MyServerComponent() {
  const responseStatus = await getApiStatus()

  return <div>API Status: {responseStatus}</div>
}

I hope this makes the intent of these APIs clearer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests

3 participants