vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.98k stars 26.98k forks source link

(AppDir) Higher order function component support #44307

Open garronej opened 1 year ago

garronej commented 1 year ago

Hello next pepoles :)

Verify canary release

Provide environment information


    Operating System:
      Platform: darwin
      Arch: x64
      Version: Darwin Kernel Version 22.1.0: Sun Oct  9 20:15:09 PDT 2022; root:xnu-8792.41.9~2/RELEASE_ARM64_T6000
    Binaries:
      Node: 16.15.1
      npm: 8.11.0
      Yarn: 1.22.19
      pnpm: 6.28.0
    Relevant packages:
      next: 13.1.0
      eslint-config-next: 11.0.1
      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/garronej/mui-next-appdir-demo/tree/higher_order_function_component

To Reproduce

git clone https://github.com/garronej/mui-next-appdir-demo
cd mui-next-appdir-demo
git checkout higher_order_function_component
yarn
yarn dev

Describe the Bug

Can't use higher order functions that returns components like:

"use client";

export function createMyComponent() {

    function MyComponent() {

        return <h1>Hello World</h1>;

    }

    return { MyComponent };

}

We get:

Server Error
TypeError: (0 , _shared_MyComponent__WEBPACK_IMPORTED_MODULE_2__.createMyComponent) is not a function
image

Expected Behavior

I would expect it to work as it makes it impossible to make existing API compatible with AppDir without introducing breaking changes.

Thank you for your work!

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

TillHeinzel commented 1 year ago

In this particular case, shouldn't it be

"use client";

export function createMyComponent() {

    function MyComponent() {

        return <h1>Hello World</h1>;

    }

    return <MyComponent />;

}

?

This way it would be an actual component being returned, right?

garronej commented 1 year ago

Hello @TillHeinzel,

No this isn't the usecase.

 "use client";

export function createMyComponent() {

    function MyComponent() {

        return <h1>Hello World</h1>;

    }

    return { MyComponent };

}

is to be used like:

// app/pages.tsx  

import React from "react";
import { createMyComponent } from "../shared/MyComponent";

const { MyComponent } = createMyComponent();

function DefaultPage() {
  return (
    <>
      <MyComponent />
    </>
  );
}

export default DefaultPage;
amlcodes commented 1 year ago

seconded, but note it is only erroring with client components

lelabo-m commented 1 year ago

I second this issue as I already mentioned this problem in an other issue #44030 about compound components.

seconded, but note it is only erroring with client components

My UI components are usually the one I want to "compose" but also the ones that require to be in "use client" files... Thus I encounter this problem frequently.