Vue force update не работает

Содержание
  1. Правильный способ заставить Vue перендерить компонент
  2. Худший вариант: перезагрузить все страницу
  3. Плохой вариант: использовать v-if хак
  4. Способ получше: можно использовать forceUpdate
  5. Лучший способ: изменение ключа
  6. Зачем нужен атрибут key в Vue?
  7. Смена ключа для принудительного повторного рендеринга компонента
  8. Дополнение от переводчика
  9. forceUpdate does not update computed fields #7395
  10. Comments
  11. nagyzsolthun commented Jan 6, 2018
  12. Version
  13. Reproduction link
  14. Steps to reproduce
  15. What is expected?
  16. What is actually happening?
  17. JounQin commented Jan 6, 2018 •
  18. yyx990803 commented Jan 6, 2018
  19. anlek commented Sep 26, 2018
  20. ypresto commented Dec 4, 2018 •
  21. mannok commented Jan 30, 2019
  22. Serval Ways to Force Update in Vue #47
  23. Comments
  24. xianshenglu commented Nov 29, 2018
  25. xianshenglu commented Dec 1, 2018
  26. Auto Update with Vue’s Reactivity System
  27. $forceUpdate
  28. Reassign
  29. v-if/key
  30. No forceUpdate() in Vue 3 with compositionAPI #3562
  31. Comments
  32. mannok commented Apr 8, 2021
  33. Version
  34. Reproduction link
  35. Steps to reproduce
  36. What is expected?
  37. What is actually happening?
  38. HcySunYang commented Apr 8, 2021 •
  39. mannok commented Apr 8, 2021
  40. HcySunYang commented Apr 8, 2021
  41. mannok commented Apr 8, 2021
  42. HcySunYang commented Apr 8, 2021
  43. mannok commented Apr 8, 2021
  44. HcySunYang commented Apr 8, 2021
  45. mannok commented Apr 8, 2021
  46. mannok commented Apr 8, 2021
  47. posva commented Apr 8, 2021
  48. LinusBorg commented Apr 8, 2021 •
  49. HcySunYang commented Apr 8, 2021
  50. mannok commented Apr 8, 2021
  51. posva commented Apr 8, 2021 •
  52. HcySunYang commented Apr 9, 2021
  53. LinusBorg commented Apr 9, 2021
  54. posva commented Apr 9, 2021
  55. yyx990803 commented Apr 10, 2021 •
  56. mannok commented Apr 10, 2021

Правильный способ заставить Vue перендерить компонент

Эта публикация является любительским переводом статьи «The correct way to force Vue to re-render a component» от Майкла Тиссена.

Иногда бывает так, что реактивности Vue не хватает, и вам нужно перерендерить компонент. Или вам нужно сбросить DOM и начать сначала.

Так как же правильным образом заставить Vue перерендерить компонент?

Ответ прост. Правильный путь — использовать :key в компоненте. Когда вам нужно перерендерить компонент, вы просто меняете значение ключа и Vue обновит компонент.

Довольно просто, не так ли? Есть также и другие способы:

  • Худший вариант: обновить всю страницу,
  • Плохой вариант: использовать v-if хак,
  • Чуть лучше: использовать встроенный в Vue метод forceUpdate ,
  • Лучший вариант: использовать изменение ключа.

Обратите внимание! Если вы столкнулись с ситуацией, в которой вам нужно перерендерить компонент, вероятно, есть более правильный способ решить задачу. Скорее всего, вы не до конца разобрались с чем-то из этого: 1. Реактивность Vue, 2. Computed-свойства, 3. Watch-свойства, 4. Не используете :key атрибут для v-for .

А теперь рассмотрим доступные способы перерендерить компонент. Почти все из них заменяемы на вариант с изменением ключа, он рассмотрен в самом конце статьи.

Худший вариант: перезагрузить все страницу

Этот способ — примерно то же самое, что перезагрузка компьютера каждый раз, когда вы хотите закрыть какое-нибудь приложение. Звучит странно, правда?

Полагаю, это и правда может когда-то вам помочь. Однако это ужасное решение, поэтому не используйте его. Совсем.

Лучше посмотрите, что вы можете использовать ещё.

Плохой вариант: использовать v-if хак

Vue содержит директиву v-if, которая позволяет рендерить компонент или часть компонента только тогда, когда условие возвращает истину. Если в условии ложь, то всё что внутри не отрендерится и не будет существовать в DOM.

Давайте посмотрим, как это выглядит на практике.

Добавьте v-if в ваш шаблон:

В секции script добавьте метод, который использует функцию nextTick :

Вот что происходит в этом коде:

  1. Сначала renderComponent установлено в true, поэтому компонент my-component рендерится
  2. Когда мы вызываем forceRerender , мы сразу устанавливаем renderComponent в false
  3. Мы прекращаем рендеринг my-component , потому что v-if директива содержит ложь
  4. На следующем шаге ( nextTick ) мы возвращаем renderComponent в true
  5. Теперь v-if содержит истину, поэтому мы снова рендерим компонент my-component

В этом примере есть два важных момента, которые важны для понимания того, как это работает. Первое — мы должны дождаться nextTick, иначе мы не увидим никаких изменений.

В Vue tick (тик) — это один цикл обновления DOM. Vue собирает все обновления в одном тике, и в конце этого тика обновляет то, что отображается в DOM в процессе этих обновлений. Если мы не дождёмся следующего тика, то наши изменения свойства renderComponent перезапишут сами себя и ничего не изменится. Поэтому мы используем nextTick .

Читайте также:  Не работает звук магнитола мазда 3

Второе, Vue создаст совершенно новый компонент, когда мы отрендерим его второй раз. Vue уничтожит первый компонент и создаст новый. Это значит, что наш новый my-component пройдёт все хуки жизненного цикла компонента — created , mounted

Кстати, вы можете использовать nextTick с промисами:

Тем не менее, это не очень хорошее решение. Скорее, это хак. Поэтому давайте посмотрим, что ещё мы можем использовать.

Способ получше: можно использовать forceUpdate

Это один из двух способов, который отлично решает проблему. При этом, он официально поддерживается Vue и не является хаком или чем-то подобным.

Обычно Vue реагирует на изменения в зависимостях, обновляя представление. Однако, когда вы запускаете forceUpdate, вы можете принудительно запустить обновление представления, даже если зависимости никак не изменились.

И вот здесь большинство людей делает множество серьёзных ошибок.

Если Vue автоматически обновляет всё когда что-то меняется, то зачем нам самим заставлять его что-то обновлять?

Причина в том, что иногда реактивность Vue может сбивать с толку. Мы думаем, что Vue отреагирует на изменения свойства или переменной, но этого не происходит. Есть также определённые ситуации, когда реактивность Vue вообще не распознаёт ваши изменения.

Стоит отметить, что forceUpdate всё же не лучший способ решения задачи. Используйте его аккуратно.

There are two different ways that you can call forceUpdate , on the component instance itself as well as globally:

Важно: этот способ не обновляет computed-свойства. Вызов forceUpdate только заставляет шаблон перерендерится.

Лучший способ: изменение ключа

Что за ключ? Сейчас во всё разберёмся. Вообще, существует много ситуаций, когда перерендеринг может действительно вам потребоваться.

Для того, чтобы сделать это надлежащим образом, мы свяжем наш компонент с атрибутом key . Так Vue свяжет компонент с отдельным куском данных. И если ключ при изменениях останется прежним, то Vue не обновит компонент, а вот если ключ поменяется — Vue избавится от старого компонент и создаст новый. То, что нам нужно!

Давайте сперва пробежимся по тому, что такое key и почему нам нужно его использовать.

Зачем нужен атрибут key в Vue?

Давайте представим, что вы рендерите список компонентов, у которых есть одно или несколько из этих свойств:

  • У компонента есть локальный стейт,
  • У компонента есть логика инициализации: что-то, что использует mounted или created хуки,
  • Не реактивные DOM-манипуляции: обычно это jQuery-решения или стандартные JS API.

Если вы отсортируете этот список или обновите его каким-либо образом, вам нужно будет повторно отрендерить все части этого списка. Вряд вы захотите перерендерить вообще все элементы этого списка, лучше затронуть лишь то, что изменилось.

Для помощи Vue в отслеживании таких изменений мы внедряем атрибут key. Использование индекса массива тут не поможет, поскольку индекс не привязан к конкретным объектам в нашем списке.

Here is an example list that we have:

Если мы отрендерим список с использованием индексов, то получим это:

Если мы удалим Марину, то получим:

Индекс, который был связан с Николаем изменился, хотя Николай всё ещё Николай. При этом, Николай перерендерится, хотя мы этого не хотели.

В нашей ситуации подойдёт какой-то уникальный ID, давайте добавим его.

Когда мы удаляли Марину из нашего списка, Vue удалил компоненты для Марины и Николая, а затем создал новый компонент для Николая. Теперь, когда Vue знает ID, он сохранит два компонента Вани и Николая, и удалит лишь компонент Марины.

Если мы добавим ещё кого-то в список, то Vue знает, что может сохранить текущие компоненты и просто создать один дополнительный. Это действительно полезно, когда у вас есть более сложные компоненты с логикой, собственным состоянием, имеют логику инициализации или выполняют какие-то манипуляции с DOM.

А теперь давайте продолжим с лучшим методом для принудительного повторного рендеринга компонентов в Vue.

Смена ключа для принудительного повторного рендеринга компонента

Наконец-то, лучший способ принудительного повторного рендеринга компонента (по мнению автора, конечно же).

Вы применяете эту стратегию назначения ключей дочерним элементам, но каждый раз, когда вы хотите повторно отрендерить компонент, вы просто обновляете ключ.

Вот простой пример того, как это работает:

Каждый раз, когда мы в компоненте вызываем forceRerender , наш пропс componentKey изменяется. Это в свою очередь приводит к тому, что Vue узнаёт когда нужно уничтожить инстанс компонента и создать новый.

В результате вы получаете дочерний компонент, который способен сам себя переинициализировать и сбросить своё состояние. Простой и элегантный способ решения проблемы.

Читайте также:  Настроить режим разметки word

И помните, что если вы столкнулись с ситуацией, когда вам нужно принудительно перерендерить компонент, то вероятно вы делаете что-то не лучшим образом. Если всё же вам нужно как-то перерендерить компонент, то выбирайте способ с привязкой ключа.

Дополнение от переводчика

Стоит упомянуть отдельно Vuex и связанную с ним реактивность. Дело в том, что если у вас в глобальном сторе хранится сложный объект или многомерный массив, то Vue не сможет отслеживать изменения в них, если делать это неправильно. В документации Vue, в описании реактивности, есть информация о том, как работать со сложными объектами и массивами, чтобы достичь реактивности.

Источник

forceUpdate does not update computed fields #7395

Comments

nagyzsolthun commented Jan 6, 2018

Version

Steps to reproduce

  1. build project
  2. open build/build.html
  3. wait 2 seconds

What is expected?

«last update time» to change

What is actually happening?

«last update time» does not change

The text was updated successfully, but these errors were encountered:

JounQin commented Jan 6, 2018 •

As I know, forceUpdate is only used to force update UI, not for inter computed data.

yyx990803 commented Jan 6, 2018

As @JounQin pointed out: $forceUpdate only force the view to re-render, not the computed properties. Your computed property should not contain an external non-reactive variable (time), which makes it impure.

anlek commented Sep 26, 2018

@yyx990803 Any reference to how to make a updatable time work in the UI?

ypresto commented Dec 4, 2018 •

@anlek methods: are called on $forceUpdate . Move time function from computed to methods (don’t forget to change time to time() ) and it should work as expected.

mannok commented Jan 30, 2019

@yyx990803 You are right. It won’t recompute the properties. However, I encounter another issue today.
$forceUpdate is not updating reactive variable too!

for example:
template part: <>
data in script part: data() < return < attr: 'foo' >>

If I update attr and the content in console by vm.$refs[‘lbl’].setAttribute(‘data-attr’, ‘bbb’) and vm.$refs[‘lbl’].innerText = ‘ccc’
follow by vm.$forceUpdate() , only the innerText part updated.

Источник

Serval Ways to Force Update in Vue #47

Comments

xianshenglu commented Nov 29, 2018

when you want to totally re-render the component, use key instead of $forceUpdate. Sometimes, it can solve the problem which $forceUpdate can’t solve.

The text was updated successfully, but these errors were encountered:

xianshenglu commented Dec 1, 2018

I have to mention this before we go on. As the doc-Forcing-an-Update says:

If you find yourself needing to force an update in Vue, in 99.99% of cases, you’ve made a mistake somewhere.

When I come back to write a blog, I find it’s totally true. Well, let’s begin. Here is the demo code based on element-ui@2.4.11 and vue@2.5.17:

Auto Update with Vue’s Reactivity System

Go check the doc.

$forceUpdate

For example, if someone made a mistake and wrote the code like

You will not see the data update because you just add an nonreactive attribute. In this case, you might need app.$forceUpdate() . However, better idea is using code like:

Reassign

However, it’s common to use third party components. In this case, it may not be easy to modify the component if we find something not good. For example, if we sort the data using:

Here is the result:

The part above the hr works as expected while the el-tree doesn’t change even you use $forceUpdate . So, in this case, what can we do?

We can make it update by reassigning like:

Until now, every thing about force update has been solved. I haven’t met problems which can’t be solved by ways above. However, there is some way stronger I have to mention.

v-if/key

In some cases, we do need to destroy and rebuild the component. But I didn’t find any API about rebuild except this issue. Some guys said we can rebuild using v-if=»isElTreeShow» :

Источник

No forceUpdate() in Vue 3 with compositionAPI #3562

Comments

mannok commented Apr 8, 2021

Version

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()

Читайте также:  Sintetiki net почему не работает

What is actually happening?

I cannot call $forceUpdate()

The text was updated successfully, but these errors were encountered:

HcySunYang commented Apr 8, 2021 •

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

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

mannok commented Apr 8, 2021

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

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

Thanks @HcySunYang, is i stand for instance?

HcySunYang commented Apr 8, 2021

Oh. sorry. yes, that should be instance

mannok commented Apr 8, 2021

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 Apr 8, 2021

Should be queuePostFlushCb :

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

mannok commented Apr 8, 2021

@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 Apr 8, 2021

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

mannok commented Apr 8, 2021

mannok commented Apr 8, 2021

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 Apr 8, 2021

$forceUpdate() is still there:

LinusBorg commented Apr 8, 2021 •

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 Apr 8, 2021

Yeah, I agree with @LinusBorg

mannok commented Apr 8, 2021

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

posva commented Apr 8, 2021 •

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?

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 Apr 9, 2021

LinusBorg commented Apr 9, 2021

we could alternatively add it to context?

posva commented Apr 9, 2021

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 Apr 10, 2021 •

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 Apr 10, 2021

@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.)

Источник

Оцените статью