TheEdoRan / next-safe-action

Type safe and validated Server Actions in your Next.js project.
https://next-safe-action.dev
MIT License
2.29k stars 35 forks source link

[PERF] `useOptimisticAction`'s `updateFn` runs too many times #255

Closed ScreamZ closed 2 months ago

ScreamZ commented 2 months ago

Are you using the latest version of this library?

Is there an existing issue for this?

Describe the bug

Hello,

I'll describe my expected features and behavior and then show you the issue with a little reproduction link.

[!NOTE] EDIT: After some investigations, this shouldn't cause big issues as it's a pure function (and a requirement). But still, why this happens?

Context

I am trying to manage a list of chat messages.

On the first render, I get the last X messages from the server and pass them as initialMessages to a useState of type array of strings.

Therefore this initial data set can be enriched by loading older messages using pagination and/or by adding new messages by sending them through the chat.

The server action responds to messages to add (kind of a ChatGPT exchange), this is not web socket-based.

To achieve that, I'm using useOptimisticAction from next-safe-action.

My issue is that updateFn is running multiple time in a row, then my onSuccess run one time. (It could be acceptable at that point), but then updateFn run again some times.

I don't understand why.

I was suspecting Strict mode, but this is more than 2 times. And why this final call ?

Current sandbox

Screenshot 2024-09-03 at 10 03 39

On my real project this even run more and more times

image

Reproduction steps

https://codesandbox.io/p/devbox/optimistic-multiple-run-k6slk6

Expected behavior

This shouldn't run multiple time ?

Minimal reproduction example

https://codesandbox.io/p/devbox/optimistic-multiple-run-k6slk6

Operating System

MacOS

Library version

7.8.1

Next.js version

14.2.1

Node.js version

20.x.x

Additional context

No response

TheEdoRan commented 2 months ago

This is a bit tricky. I've done some tests without next-safe-action and found out that the reducer function of useOptimistic hook gets called three times per invocation, so this is the base behavior. If I instead use the useOptimisticAction hook from next-safe-action, the updateFn is invoked 2x3 or 3x3 times, depending on the execution status, so something is causing one or two re-renders. I've tried to use a ref for updateFn, tried to disable callbacks and executeOnMount functionality, but the behavior does not change. Not sure why this happens honestly, but it doesn't seem to cause bugs or glitches in the UI. If you find a solution feel free to submit a PR with the fix, gonna keep this issue open for now, thanks.

ScreamZ commented 2 months ago

This is a bit tricky. I've done some tests without next-safe-action and found out that the reducer function of useOptimistic hook gets called three times per invocation, so this is the base behavior. If I instead use the useOptimisticAction hook from next-safe-action, the updateFn is invoked 2x3 or 3x3 times, depending on the execution status, so something is causing one or two re-renders. I've tried to use a ref for updateFn, tried to disable callbacks and executeOnMount functionality, but the behavior does not change. Not sure why this happens honestly, but it doesn't seem to cause bugs or glitches in the UI. If you find a solution feel free to submit a PR with the fix, gonna keep this issue open for now, thanks.

I think that's why they said this must be a pure function and not cause any side effects. Figured out after some time that my bug wasn't related to this, but it's interesting to understand the behavior.

Thanks for your investigation