Skip to content

Conversation

ZKunZhang
Copy link
Contributor

Before submitting the PR, please make sure you do the following

⚠️ Slowing down new functions

Warning: Slowing down new functions

As the VueUse audience continues to grow, we have been inundated with an overwhelming number of feature requests and pull requests. As a result, maintaining the project has become increasingly challenging and has stretched our capacity to its limits. As such, in the near future, we may need to slow down our acceptance of new features and prioritize the stability and quality of existing functions. Please note that new features for VueUse may not be accepted at this time. If you have any new ideas, we suggest that you first incorporate them into your own codebase, iterate on them to suit your needs, and assess their generalizability. If you strongly believe that your ideas are beneficial to the community, you may submit a pull request along with your use cases, and we would be happy to review and discuss them. Thank you for your understanding.


Description

  • adjust the useStorage key watcher to flush in the post phase (sync mode unchanged), ensuring we don’t read from
    storage before same-tick explicit writes land.
  • add a regression test covering “change key and value within the same tick” to prove the new value now sticks, and
    update the prior expectation that relied on the old behaviour.

Additional context

  • tests: pnpm vitest run packages/core/useStorage/index.test.ts

@dosubot dosubot bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Sep 23, 2025
Copy link

pkg-pr-new bot commented Sep 23, 2025

Open in StackBlitz

@vueuse/components

npm i https://pkg.pr.new/@vueuse/components@5059

@vueuse/core

npm i https://pkg.pr.new/@vueuse/core@5059

@vueuse/electron

npm i https://pkg.pr.new/@vueuse/electron@5059

@vueuse/firebase

npm i https://pkg.pr.new/@vueuse/firebase@5059

@vueuse/integrations

npm i https://pkg.pr.new/@vueuse/integrations@5059

@vueuse/math

npm i https://pkg.pr.new/@vueuse/math@5059

@vueuse/metadata

npm i https://pkg.pr.new/@vueuse/metadata@5059

@vueuse/nuxt

npm i https://pkg.pr.new/@vueuse/nuxt@5059

@vueuse/router

npm i https://pkg.pr.new/@vueuse/router@5059

@vueuse/rxjs

npm i https://pkg.pr.new/@vueuse/rxjs@5059

@vueuse/shared

npm i https://pkg.pr.new/@vueuse/shared@5059

commit: f0d599d

Copy link
Member

@ilyaliao ilyaliao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't want users to set flush: pre, we should restrict it through types

@ilyaliao
Copy link
Member

Also, I'm wondering if we should never allow users to pass 'pre', or maybe we just need to simply change the default value to 'sync'.

@ZKunZhang
Copy link
Contributor Author

Also, I'm wondering if we should never allow users to pass , or maybe we just need to simply change the default value to .'pre'``'sync'

  1. Type restriction approach: While it provides type safety, it would force users to modify existing code, making it a Breaking Change.
  2. Default value modification approach: Although it seems simple, it changes the default behavior for all users, and testing has confirmed it would break existing logic.

@ilyaliao
Copy link
Member

  1. Type restriction approach: While it provides type safety, it would force users to modify existing code, making it a Breaking Change.
  2. Default value modification approach: Although it seems simple, it changes the default behavior for all users, and testing has confirmed it would break existing logic.

oh, I see, because flush is also used elsewhere

Then I just want to confirm if we can always set it to sync or post

@ZKunZhang
Copy link
Contributor Author

  1. Type restriction approach: While it provides type safety, it would force users to modify existing code, making it a Breaking Change.
  2. Default value modification approach: Although it seems simple, it changes the default behavior for all users, and testing has confirmed it would break existing logic.

oh, I see, because flush is also used elsewhere

Then I just want to confirm if we can always set it to sync or post

Current Logic
const keyWatcherFlush = flush === 'sync' ? 'sync' : 'post'

Why we cannot always set it to 'sync':

  1. Performance issues: 'sync' executes immediately without batching optimizations
  2. Violates user intent: When users set flush='pre', there's a reason - forcing 'sync' goes against their intention
  3. Vue reactivity best practices: Vue defaults to 'pre' for better performance and batching

Why we cannot always set it to 'post':

  // If we always use 'post', when user sets flush='sync':
  const { flush = 'sync' } = options
  // Data watcher: 'sync' (immediate execution)
  // Key watcher: 'post' (delayed execution)
  // This would cause execution order issues

Specific scenario problems:

When key and data change simultaneously:

  • User sets sync: Expects immediate synchronous execution
  • If key watcher uses post: Will execute in next tick, breaking sync semantics

Edge case example:

 // User expects synchronous behavior
  const storage = useStorage('key', 'default', storage, { flush: 'sync' })
  storage.value = 'newValue' // Data watcher runs immediately ('sync')
  key.value = 'newKey'       // If key watcher is 'post', runs later - wrong!

Conclusion:
The conditional logic is necessary because it ensures:

  • Respects user's flush configuration intent
  • Maintains correct execution order
  • Prevents key changes from overwriting data changes

Did my answer solve your problem?

@9romise
Copy link
Member

9romise commented Sep 24, 2025

Based on your changes, passing pre to the flush option would become meaningless. This could break existing usage for users who use the default value or explicitly set pre, and likely cause unnecessary confusion.
Also, changing the default value would be a breaking change.

I'm leaning towards refining the type definitions for the flush option.

@ZKunZhang
Copy link
Contributor Author

Based on your changes, passing pre to the flush option would become meaningless. This could break existing usage for users who use the default value or explicitly set pre, and likely cause unnecessary confusion. Also, changing the default value would be a breaking change.

I'm leaning towards refining the type definitions for the flush option.

Thanks for the feedback! You raise valid concerns about the potential impact on existing usage.

Looking at this more carefully, I think there are a few ways to approach this:

  1. Refine type definitions approach: As you suggested, we could create more specific flush option types that better communicate the actual behavior and constraints.

  2. Alternative solution: Instead of changing the flush timing, we could explore using a different approach like:

    • Using a single watcher that handles both key and data changes
    • Or using a micro-task queue to ensure proper execution order without changing the flush API
  3. If we keep the current approach: We could consider this as a bug fix rather than a breaking change, since the current behavior (data updates being overwritten by key changes in the same tick) is
    arguably incorrect. However, I understand the concern about user expectations.

The core issue we're solving is that when both key and data change in the same tick, we want to preserve the data update rather than having it overwritten by the key change.

Would you prefer to explore the type definition approach first, or would you like to see an alternative implementation that doesn't modify the flush behavior?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size:S This PR changes 10-29 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BUG | useStorage | The new value is ignored when changing both the key and value synchronously
3 participants