vuejs / composition-api

Composition API plugin for Vue 2
https://composition-api.vuejs.org/
MIT License
4.19k stars 343 forks source link

`flush: 'sync'` option of `watchEffect` is inconsistent with the behavior of Vue 3 #770

Closed John60676 closed 3 years ago

John60676 commented 3 years ago

Description

In composition-api, account change will not trigger this watch, when flush: 'sync' option is set, but Vue 3 will trigger this watch.

setup() {
  const account = ref("John")
  const name = ref("")

  watchEffect(
    () => {
      name.value = account.value
      // in Vue 3, `account` change will trigger this watch, 
      // but in composition-api it will not
      console.log("watch")  
    },
    {
      flush: "sync",
    }
  )
  return { account, name }
}

Reproduce

Vue 2 demo: https://codesandbox.io/s/vue2-watcheffect-yebvl?file=/src/App.vue

Vue 3 demo: https://codesandbox.io/s/vue3-watcheffect-jy20t?file=/src/App.vue

ygj6 commented 3 years ago

This PR https://github.com/vuejs/composition-api/pull/724 could solve the issue, but it's not the best solution.

sunyanzhe commented 3 years ago

I think the reason for this problem is this:https://github.com/vuejs/composition-api/blob/9566e6363da289951073ac5b29810c0577a64648/src/reactivity/reactive.ts#L97

When observe is executed, target will change to accessor mode. Target must have getter/setter. When the setter is triggered, getter.call(target) will collect dependencies. That's why dependencies are collected despite assignment

I know this code is to avoid the data that is originally accessors, but this logic already exists in defineReactive, why repeat implementation.

sorry for the bad English

ygj6 commented 3 years ago

Has been solved by https://github.com/vuejs/composition-api/pull/786.