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

Zustand breaks with NextJS 13 when enabling appDir (Cannot read properties of null (reading 'useDebugValue')) #1395

Closed
lucasmerlin opened this issue Oct 27, 2022 · 39 comments · Fixed by #2154
Labels
help wanted Please someone help on this

Comments

@lucasmerlin
Copy link

I created a minimal reproduction here:
https://stackblitz.com/edit/nextjs-egfcaj?file=package.json

It throws the following error:

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
TypeError: Cannot read properties of null (reading 'useDebugValue')
    at Module.useDebugValue (/home/projects/nextjs-egfcaj/node_modules/react/cjs/react.development.js:1659:23)
    at useStore (file:///home/projects/nextjs-egfcaj/node_modules/zustand/esm/index.mjs:37:10)
    at useBoundStore (file:///home/projects/nextjs-egfcaj/node_modules/zustand/esm/index.mjs:42:51)
    at __WEBPACK_DEFAULT_EXPORT__ (webpack-internal:///./pages/index.js:20:19)

If you remove the "appDir: true" line from next.config.js, the counter works as expected. The weirdest thing is that the project doesn't even use the app dir, just enabling the flag is enough for the error to happen.
After a bit of debugging in my project, comparing the useDebugValue that is imported by zustand and the one I imported in my component, they are not equal. Seems like the multiple react copies error, although there is only one react version installed.

I also tried zustand version 3, it throws a similar error, but with the useReducer hook instead of useDebugValue.
I also tried the version from here: #1392 but it didn't help.

Relevant NextJS discussion: vercel/next.js#41236

@dai-shi dai-shi added the help wanted Please someone help on this label Oct 27, 2022
@Sec-ant
Copy link

Sec-ant commented Nov 1, 2022

Does anyone like me think this might have something to do with the "Dual Package Hazard" caused by multiple instances of a same dependency?

The reason that state is an issue is because both the CommonJS and ES module versions of the package might get used within an application; for example, the user's application code could import the ES module version while a dependency requires the CommonJS version. If that were to occur, two copies of the package would be loaded in memory and therefore two separate states would be present. This would likely cause hard-to-troubleshoot bugs.

@dai-shi
Copy link
Member

dai-shi commented Nov 1, 2022

Zustand library itself shouldn't suffer from Dual Package Hazard, because it doesn't have module state. (On the other hand, Jotai and Valtio have module state, so they can suffer.)

@Sec-ant
Copy link

Sec-ant commented Nov 2, 2022

@dai-shi yeah you're right it is not caused by zustand library itself. I did some test and I saw this error is triggered when useDebugValue is called on the server side. This simple patch will make the code work. Not sure about the proper way to fix this though:

diff --git a/node_modules/zustand/esm/index.mjs b/node_modules/zustand/esm/index.mjs
index 2c76b55..73ad140 100644
--- a/node_modules/zustand/esm/index.mjs
+++ b/node_modules/zustand/esm/index.mjs
@@ -13,7 +13,9 @@ function useStore(api, selector = api.getState, equalityFn) {
     selector,
     equalityFn
   );
-  useDebugValue(slice);
+  if (typeof window !== "undefined") {
+    useDebugValue(slice);
+  }
   return slice;
 }
 const createImpl = (createState) => {

@dai-shi
Copy link
Member

dai-shi commented Nov 2, 2022

Ah, maybe because React doesn't provide ESM.
Can you try this?

// ./node_modules/zustand/esm/index.mjs
import React from 'react'

// ...
  React.useDebugValue(slice)

@Sec-ant
Copy link

Sec-ant commented Nov 2, 2022

Ah, maybe because React doesn't provide ESM. Can you try this?

// ./node_modules/zustand/esm/index.mjs
import React from 'react'

// ...
  React.useDebugValue(slice)

nope, this won't work, same error.

@Sec-ant
Copy link

Sec-ant commented Nov 2, 2022

These two issues might be relevant? (but neither solves this problem)
vercel/next.js#41929
react-bootstrap/react-bootstrap#6475
and this doc:
https://beta.nextjs.org/docs/rendering/server-and-client-components

@Sec-ant
Copy link

Sec-ant commented Nov 2, 2022

I start thinking that this issue may be a misuse of the nextjs 13 appDir feature? If I follow the docs to setup/migrate the app to nextjs 13. Everything just works: https://stackblitz.com/edit/nextjs-od7fky?file=app/Button.jsx Maybe we shouldn't keep the appDir true while using the pages dir?

@dai-shi
Copy link
Member

dai-shi commented Nov 3, 2022

@alizaeda
Copy link

alizaeda commented Nov 3, 2022

Same issue without appDir is enabled

@jescalan
Copy link

jescalan commented Nov 9, 2022

Hi everyone! Just want to note that we're looking into this on the nextjs team.

@TomBeckett
Copy link

@jescalan Good news! Anywhere we can track progress of the investigation?

@jescalan
Copy link

No, it's generally in our company slack. We will have something out for this soon though, it's an active priority. The core issue is the ESM thing mentioned above, which is also causing bugs with a number of other things.

@btran946
Copy link

@jescalan any suggestions on state management tools similar to Zustand in the mean time?

@nhatimme
Copy link

nhatimme commented Nov 15, 2022

We also facing a issue when we want to load the store into a file which is located at /app/contact.tsx (It gives an error like: Unhandled Runtime Error Error: useRef is not a function)

contact.tsx

import useBearStore from '../../stores/cart'

function HomePage() {
  const { bears } = useBearStore();
  return (
    <main>
      Contact
      { bears }
    </main>
  )
}

export default HomePage;

@adriannecris
Copy link

adriannecris commented Nov 15, 2022

We also facing a issue when we want to load the store into a file which is located at /app/contact.tsx (It gives an error like: Unhandled Runtime Error Error: useRef is not a function)

contact.tsx

import useBearStore from '../../stores/cart'

function HomePage() {
  const { bears } = useBearStore();
  return (
    <main>
      Contact
      { bears }
    </main>
  )
}

export default HomePage;

@nhatimme Have you tried adding 'use client'; at the very first line. Reference in this link

@nhatimme
Copy link

@adriannecris Thanks. So it is impossible to use it as Server Side component?

@jescalan
Copy link

jescalan commented Nov 18, 2022

Yeah, it's never going to be possible to use zustand in a server component, as state is not supported by server components in general. It works quite well in app directory right now as long as you are using client components. Actually I think it may be working fine with the latest version of nextjs, I just made a reproduction repo here and everything is working quite nicely. This includes an example of it working both in pages and app directory.

Let me know if I missed anything or if anyone has a reproduction with the latest version - hopefully this can be closed out!

Edit: confirmed that updating to 13.0.3 in the original stackblitz fixes the issue

@nhatimme
Copy link

@jescalan: Perfect.

@rumrum28
Copy link

rumrum28 commented Dec 6, 2022

still having this issue im 13.0.6 now

@vlausargs
Copy link

can use it just fine after add "use client"

@wootra
Copy link

wootra commented Feb 3, 2023

@adriannecris Thanks. So it is impossible to use it as Server Side component?

you may be able to use useBearStore.setState(...) / useBearStore.getState().myVal in the server side without an issue.

@wootra
Copy link

wootra commented Feb 3, 2023

all client based hook should be used after adding 'use client' on top of the file. But Next13 does not give a good error message where is missing. That is really tough since I have to find it manually.

@Scdales
Copy link

Scdales commented Mar 1, 2023

can use it just fine after add "use client"

@vlausargs Which files are you labelling 'use client'? I have tried adding it to all files that import anything from zustand and I'm still seeing the error appearing:

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
TypeError: Cannot read properties of null (reading 'useDebugValue')

@wootra
Copy link

wootra commented Mar 5, 2023

can use it just fine after add "use client"

@vlausargs Which files are you labelling 'use client'? I have tried adding it to all files that import anything from zustand and I'm still seeing the error appearing:

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
TypeError: Cannot read properties of null (reading 'useDebugValue')

it could be because of a lot of reason and next 13 sometimes gives not even relative error. worst part is it ia hard to tell where is the origin of the error.. you might want to move all page and app path to somewhere else not in the app directory to narrow down where is the origin of the issue.
but some of cases you may check to figure out where is it coming from, tty below.. not 100% sure though.
make sure if you wrap the component that uses "use client" as a separated component to use it in the server component. you may be using "use client" in the page.jsx file. async component cannot be used with client component.
you may call hook after returning content.
you shouldnt use hook in the server or async component.

@kcrwfrd
Copy link

kcrwfrd commented May 17, 2023

We encountered this error when using Next.js 13.4 with a custom server, even though we were not using the new app dir. I believe the problem is explained here: vercel/next.js#49355 (comment)

We've fixed this for now by specifying our Next.js version as ~13.3.4

@sushantdhiman
Copy link

It seems like this issue is fixed with next@13.4.3 for custom server (my use case). This issue is tracked in Next.js vercel/next.js#49355, it is not related to just zustand. I think this issue should be closed.

@coder-abdo
Copy link

it is working fine when I tried it you can see it below example:
https://codesandbox.io/p/sandbox/cocky-mcclintock-38j52j?file=%2Fapp%2Fpage.tsx%3A13%2C28

@ocodista
Copy link

I think this issue should be closed.

@lucasmerlin
Copy link
Author

Zustand has been working fine in my nextjs project with app dir, so I'm closing this issue now.

@adarshaacharya
Copy link

adarshaacharya commented Sep 4, 2023

still getting same error, on pages directory.
Using following version of next and zustand:

    "next": "13.4.19",
    "zustand": "^4.4.1"

@Emiliano-Bucci
Copy link

Issue seems to appear again with next 13.4.19

@hazzo
Copy link

hazzo commented Sep 13, 2023

still getting same error, on pages directory. Using following version of next and zustand:

    "next": "13.4.19",
    "zustand": "^4.4.1"

Did you try deleting .next folder?

@OlegLustenko
Copy link

OlegLustenko commented Oct 27, 2023

It started reproducing again in Next v14, pages dir in the Docker. App dir is fine.

I've tried ppr: true won't help
image

Zustand version is 4.4.4

@dai-shi
Copy link
Member

dai-shi commented Oct 28, 2023

Please try #2154
https://ci.codesandbox.io/status/pmndrs/zustand/pr/2154
☝️ Find "Local Install Instructions"

@OlegLustenko
Copy link

OlegLustenko commented Oct 28, 2023

it was fast! Thanks!

@JanRuettinger
Copy link

Issue not fixed yet it seems. I face the issue with "next": "13.4.19", "zustand": "^4.4.1" and page dir.

@OlegLustenko
Copy link

@JanRuettinger update Zustand to the latest version

@AnimeshTimsina
Copy link

This issue appears again on "next": "14.0.3", "zustand": "^4.4.7"

@SysWhiteDev
Copy link

Issue is here again on "next": "14.1.0", "zustand": "^4.5.0"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Please someone help on this
Projects
None yet
Development

Successfully merging a pull request may close this issue.