vercel / next.js

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

Stale values returned from useOptimistic when state changes #57662

Closed dorshinar closed 8 months ago

dorshinar commented 12 months ago

Link to the code that reproduces this issue

https://github.com/dorshinar/next-optimistic-bug

To Reproduce

  1. Start application: npm run dev
  2. Observe the rendered array not changing depsite a useEffect setting the state

To illustrate the bug I have a state variable called arrFromServer in the <Form /> component, and I am passing it through useOptimistic as if I was updating data fetched from the server optimistically. The arrFromServer in a placeholder for data fetched from a Server Component, and the useEffect is a way to simulate updating the data on the server and refetching it. In the image below, the optimisticArr remains constant with 3 elements, while arrFromServer grows in an interval

Screenshot 2023-10-28 at 12 37 32

Current vs. Expected behavior

I expect useOptimistic to return the up-to-date state passed as parameter while a mutation is not in-flight. The current behavior seems to return the initial state provided to useOptimistic.

Verify canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.0.0: Fri Sep 15 14:41:43 PDT 2023; root:xnu-10002.1.13~1/RELEASE_ARM64_T6000
Binaries:
  Node: 20.7.0
  npm: 10.1.0
  Yarn: 1.22.19
  pnpm: 8.9.2
Relevant Packages:
  next: 14.0.1-canary.1
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.1.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Data fetching (gS(S)P, getInitialProps)

Additional context

No response

JesseKoldewijn commented 12 months ago

It doesn't,t look like you're using the useOptimistic hook correctly there. (But keep in mind, last time I personally used it it was still experimental)

Maybe try to create a setup just like the official docs show.

https://react.dev/reference/react/useOptimistic

Ps. This is might be better suited in the react repo rather than the Next.js one

dorshinar commented 12 months ago

Thanks for the reply @JesseKoldewijn! I might be using it wrong, but as I understand it my example should work. I've tried adding a simple echo function as the second parameter to useOptimistic, but I get the same behavior

const [optimisticArr] = useOptimistic(arrFromServer, (s) => s);

My example intentionally does not use the callback returned from useOptimistic to show that the issue is not about the optimistic update mechanism, but the internal state that useOptimistic apparently holds.

Without a form submission in progress useOptimistic should just pass the state through to my app IIUC.

JesseKoldewijn commented 12 months ago

Thanks for the reply @JesseKoldewijn!

I might be using it wrong, but as I understand it my example should work. I've tried adding a simple echo function as the second parameter to useOptimistic, but I get the same behavior


const [optimisticArr] = useOptimistic(arrFromServer, (s) => s);

My example intentionally does not use the callback returned from useOptimistic to show that the issue is not about the optimistic update mechanism, but the internal state that useOptimistic apparently holds.

Without a form submission in progress useOptimistic should just pass the state through to my app IIUC.

I will have to dig in on the exact behaviour of the useOptimistic hook again but I'll have a look for ya later todayđź‘Ť

dorshinar commented 12 months ago

I think this might indeed be a bug in React. Looking at the code for useOptimistic, specifically this line: https://github.com/facebook/react/blob/3e09c27b880e1fecdb1eca5db510ecce37ea6be2/packages/react-reconciler/src/ReactFiberHooks.js#L1416

It appears that when both queues are null (pendingQueue and baseQueue), which is, as I understand it, what happens when there are no submissions in progress, the returned value is simply the hook.memoizedState which is, as I suspect, the initial state provided to the hook.

I'll open a bug report in the React repo.

dorshinar commented 12 months ago

Opened the bug report https://github.com/facebook/react/issues/27617

dorshinar commented 8 months ago

This issue has been fixed in React https://github.com/facebook/react/issues/27617

github-actions[bot] commented 8 months ago

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.