vuejs / core

๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.76k stars 8.35k forks source link

No forceUpdate() in Vue 3 with compositionAPI #3562

Open mannok opened 3 years ago

mannok commented 3 years ago

Version

3.0.11

Reproduction link

https://jsfiddle.net/posva/km2qpwx7/

Steps to reproduce

In Vue2 we can call this.$forceUpdate() to force update a component. Once I switched to Vue 3 Composition API, seems this feature is lost... How can I get it back?

What is expected?

I can call $forceUpdate()

What is actually happening?

I cannot call $forceUpdate()

HcySunYang commented 3 years ago

This is indeed a lack of the Composition API, but you can easily use the existing API to make workarounds:

import { queueJob } from 'vue'

const Comp = {
  setup() {
    const instance = getCurrentInstance()
    const $forceUpdate = () => queueJob(instance.update)
  }
}

Maybe we need an implementation of the Composition API version of the corresponding capability, e.g.

import { forceUpdate } from 'vue'
mannok commented 3 years ago

This is indeed a lack of the Composition API, but you can easily use the existing API to make workarounds:

import { queueJob } from 'vue'

const Comp = {
  setup() {
    const instance = getCurrentInstance()
    const $forceUpdate = () => queueJob(i.update)
  }
}

Maybe we need an implementation of the Composition API version of the corresponding capability, e.g.

import { forceUpdate } from 'vue'

Thanks @HcySunYang, is i stand for instance?

HcySunYang commented 3 years ago

Oh...sorry.... yes, that should be instance

mannok commented 3 years ago

Oh...sorry.... yes, that should be instance

by the way, I don't find a function named queueJob, is it the same with nextTick?

HcySunYang commented 3 years ago

Should be queuePostFlushCb:

import { queuePostFlushCb } from 'vue'

I donโ€™t recommend this, but it seems to be the only workaround at the moment

mannok commented 3 years ago

@HcySunYang May I know what is the difference between queuePostFlushCb and nextTick? Also, why should I put the update function inside queuePostFlushCb? Can I call instance.update() instead? Thanks in advance.

HcySunYang commented 3 years ago

The queueJob will put the update task in the async queue, and can de-duplicate the update task

mannok commented 3 years ago

Thanks @HcySunYang

mannok commented 3 years ago

I found that queueJob is not exposed for us... and queuePostFlushCb does not have the ability to de-duplicate the callback. May I know if I can use queueJob here?

posva commented 3 years ago

$forceUpdate() is still there:


  setup() {
    const instance = Vue.getCurrentInstance()

    console.log(instance.proxy.$forceUpdate)
  }
LinusBorg commented 3 years ago

FWIW, I think it's still worthwhile to provide a bette way to force an update than to go through the internal component instance.

We do want people to rely on this as little as possible, which is also why we don't document anything about it's APIs - it's considered internal and more of an escape hatch for lib authors.

HcySunYang commented 3 years ago

Yeah, I agree with @LinusBorg

mannok commented 3 years ago

@LinusBorg Yes, I was stuck until I find this internal instance approach. Wish $forceUpdate can be exposed to developers.

posva commented 3 years ago

We do want people to rely on this as little as possible, which is also why we don't document anything about it's APIs - it's considered internal and more of an escape hatch for lib authors.

Yeah, what would we expose though?

export function useForceUpdate() {
  const instance = getCurrentInstance()
  return () => instance.proxy.$forceUpdate()
}

setup() {
  const forceUpdate = useForceUpdate()

  function doStuff() {
    forceUpdate()
  }
}

Since it relies on the current instance, I don't think we can directly expose forceUpdate()

Given the nature of this API, I'm not sure if it should be documented instead

HcySunYang commented 3 years ago
export function useForceUpdate() {
const instance = getCurrentInstance()
return () => instance.proxy.$forceUpdate()
}

@posva , Looks great ๐Ÿ‘

LinusBorg commented 3 years ago

we could alternatively add it to context?

posva commented 3 years ago

I think we should avoid exposing a low level utility like forceUpdate() in such a visible place like the context. I personally think we should document this rather than add useForceUpdate() because it shouldn't be used most of the time and people should search for this method and inform themselves of what it is intended for rather than just see the name with autocompletion and try to use it

yyx990803 commented 3 years ago

I've actually never for once needed forceUpdate when using Vue 3 myself. I would rather know what use case this is absolutely needed for.

mannok commented 3 years ago

@yyx990803 I used to develop geographical map with (ArcGIS JSAPI) and using Vue as my web framework. ArcGIS JSAPI has its own reactive system and seems to be implemented by getter/setter (like Vue2). However, I should avoid Vue3 to make it as reactive so that I always markRaw to those instances which belongs to this API. The problem is that Vue reactive system won't know when the instance's property is being mutated. Or I should say I know better than Vue in this case. Therefore, I know when should I call $forceUpdate() in order to update the template. (If part of the template depends on the instance's property.)

Rainer-Yu commented 2 years ago

Will there be an API for forceUpdate()? I imported a class instance (using getter/setter and Proxy but can't use vue's reactive system to wrap it) in vue3 component and need to trigger update manually

yyx990803 commented 2 years ago

@whylost wrap your state class instance in a shallowRef: https://vuejs.org/guide/extras/reactivity-in-depth.html#integration-with-external-state-systems

Rainer-Yu commented 2 years ago

@whylost wrap your state class instance in a shallowRef: https://vuejs.org/guide/extras/reactivity-in-depth.html#integration-with-external-state-systems

thanks

AimForNaN commented 10 months ago

@yyx990803 Then you could argue that exposing it for the Options API could be declared deprecated. If there's a reason to continue keeping it around for the Options API, then that same reason should be just as valid for Composition API.