watch icon indicating copy to clipboard operation
watch copied to clipboard

Test cases to add. Mutating a reactive parent.

Open Lee182 opened this issue 5 years ago • 3 comments

Just added these test cases for when mutating a reactive parent. I ran into the second issue realising the ref which I created had been overwritten. Don't know if this warning should be added to the docs which "watchers to refs that have been overwritten at the parent level will not fire".

test('should work with mutating parent', (assert) => {
  let state = reactive({
    settings: {
      blocking: {
        isEnabled: false,
        isCosmetic: false,
        whitelist: []
      }
    }
  })

  let triggered = 0
  const stop = watch(() => {
    return state.settings.blocking
  }, () => {
    triggered += 1
  })

  state.settings = {
    blocking: {
      isEnabled: true,
      isCosmetic: true,
      whitelist: []
    }
  }

  assert.is(triggered, 1)
  stop()
})

test('should not trigger when mutating parent because watching a ref that has been destroyed by the parent mutation.', (assert) => {
  let state = reactive({
    settings: {
      blocking: {
        isEnabled: false,
        isCosmetic: false,
        whitelist: []
      }
    }
  })

  let triggered = 0
  const refBlocking = ref(state.settings.blocking)
  const stop = watch(refBlocking, () => {
    triggered += 1
  })

  state.settings = {
    blocking: {
      isEnabled: true,
      isCosmetic: true,
      whitelist: []
    }
  }

  assert.is(triggered, 0)
  stop()
})

Lee182 avatar Dec 01 '20 14:12 Lee182

@Lee182 This is not how you use it, instead of

const refBlocking = ref(state.settings.blocking)

You should do

const refBlocking = toRef(state.settings, 'blocking')

See more on Vue 3's caveat. Thanks

antfu avatar Dec 01 '20 20:12 antfu

Tried const refBlocking = toRef(state.settings, 'blocking'). That fails. As a point of discussion should there be some sort of deep to ref function like lodash.get. _.get(state, 'settings.blocking'

watch on  master [!] is 📦 v0.1.6 via ⬢ v12.18.3 took 6s 
❯ pnpm run test

> @vue-reactivity/[email protected] test C:\me\dev\tabdeck\external_lib\watch
> c8 ava


  should not trigger when mutating parent because watching a ref that has been destroyed by the parent mutation.

  test\watch.spec.ts:128

   127:
   128:   assert.is(triggered, 1)
   129:   stop()

  Difference:

  - 0
  + 1

  » test/watch.spec.ts:128:10

  ─

  1 test failed
------------------|---------|----------|---------|---------|-------------------------
File              | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s       
------------------|---------|----------|---------|---------|-------------------------   
All files         |   94.18 |      100 |   88.46 |   94.18 |                         
 errorHandling.ts |   98.28 |      100 |   66.67 |   98.28 | 58                         
 index.ts         |   93.16 |      100 |    91.3 |   93.16 | 47-56,74-75,116-118,122    
------------------|---------|----------|---------|---------|-------------------------   
 ERROR  Test failed. See above for more details.

Lee182 avatar Dec 01 '20 22:12 Lee182

In my project base I've got round it using watchEffect. I just then had to mannually track changes which I know from reading the docs which watch will track changes and call the callback only on change. lazy is what the docs call this behaviour.

    this.stopWatchSettings = watchEffect(() => {
      // const blocker = state.settings.blocker
      const blocker = _.get(state, 'settings.blocker')
      this.swapBlocker({})
    }, { flush: 'post' })

Lee182 avatar Dec 01 '20 22:12 Lee182