-
Notifications
You must be signed in to change notification settings - Fork 913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hot reload problem when use keep-alive wrap router-view with a dynamic key #1332
Comments
I came here to report this issue back here, but it's already reported, so I just share the original issue from vue-router then to create a link. |
Does anyone have a work around? |
Anyone? :) |
Still nothing? |
This still persists. Is everyone using keep-alive just refreshing each time still? |
For the most part... sigh |
Very annoying. |
I am commenting |
Any workaround? |
The best workaround I found is haven't thought about it since. |
Same problem. |
Workaround: disable keep-alive for debug.
|
因为router-view 给了key 所以会白屏
keep-alive 的源码: 缓存的key 就是取的 router-view 的key;
每次hot update 的时候 cid 是会变化的 看 下面 vue-hot-reload 的源码 record.Ctor.cid = newCtor.cid
修改方法:keep-alive组件缓存 key的取法 加上 (componentOptions.Ctor as any).cid
组件全局覆盖,伪代码:
@sodatea 大佬能修复下吗,没搞过pr |
it's working!👍 |
@nailfar import Vue from "vue"
/*
* https://github.com/vuejs/vue-loader/issues/1332#issuecomment-601572625
*/
function isDef(v) {
return v !== undefined && v !== null
}
function isAsyncPlaceholder(node) {
return node.isComment && node.asyncFactory
}
function getFirstComponentChild(children) {
if (Array.isArray(children)) {
for (var i = 0; i < children.length; i++) {
var c = children[i]
if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
return c
}
}
}
}
function getComponentName(opts) {
return opts && (opts.Ctor.options.name || opts.tag)
}
function matches(pattern, name) {
if (Array.isArray(pattern)) {
return pattern.indexOf(name) > -1
} else if (typeof pattern === "string") {
return pattern.split(",").indexOf(name) > -1
} else if (isRegExp(pattern)) {
return pattern.test(name)
}
/* istanbul ignore next */
return false
}
function remove(arr, item) {
if (arr.length) {
var index = arr.indexOf(item)
if (index > -1) {
return arr.splice(index, 1)
}
}
}
function pruneCacheEntry(cache, key, keys, current) {
var cached$$1 = cache[key]
if (cached$$1 && (!current || cached$$1.tag !== current.tag)) {
cached$$1.componentInstance.$destroy()
}
cache[key] = null
remove(keys, key)
}
function pruneCache(keepAliveInstance, filter) {
var cache = keepAliveInstance.cache
var keys = keepAliveInstance.keys
var _vnode = keepAliveInstance._vnode
const cachedNameKeyMap = keepAliveInstance.cachedNameKeyMap
for (var key in cache) {
var cachedNode = cache[key]
if (cachedNode) {
var name = getComponentName(cachedNode.componentOptions)
if (name && !filter(name)) {
delete cachedNameKeyMap[name]
pruneCacheEntry(cache, key, keys, _vnode)
}
}
}
}
const patternTypes = [String, RegExp, Array]
const KeepAlive = {
name: "keep-alive",
abstract: true,
props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number],
},
created() {
this.cache = Object.create(null)
this.cachedNameKeyMap = Object.create(null)
this.keys = []
},
destroyed() {
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},
mounted() {
this.$watch("include", val => {
pruneCache(this, name => matches(val, name))
})
this.$watch("exclude", val => {
pruneCache(this, name => !matches(val, name))
})
},
render() {
const slot = this.$slots.default
const vnode = getFirstComponentChild(slot)
const componentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, cachedNameKeyMap, keys } = this
const key =
vnode.key == null
? // same constructor may get registered as different local components
// so cid alone is not enough (#3269)
componentOptions.Ctor.cid +
(componentOptions.tag ? `::${componentOptions.tag}` : "")
: vnode.key
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
// prune old component for hmr
if (name && cachedNameKeyMap[name] && cachedNameKeyMap[name] !== key) {
pruneCacheEntry(cache, cachedNameKeyMap[name], keys)
}
cachedNameKeyMap[name] = key
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
},
}
// ovveride original keep-alive
process.env.NODE_ENV === "development" && Vue.component("KeepAlive", KeepAlive) |
For me, this only happens when I'm adding new line / deleting existing line to the template. If I'm modifying existing line, the hot reload works fine. |
The newline issue is tracked here: #1682 |
@nailfar & @ericwu-wish thank you so much for the direction here. I would have been completely lost without the callout regarding The solution I landed on is pretty much on par with what @nailfar wrote up which I tested and have verified in multiple scenarios. To make this easier I've created a plugin which will resolve the issue for anyone interested: https://www.npmjs.com/package/vue-keep-alive-dev Though, honestly, I wonder if there's really much harm in appending the cid to the cache globally as it stays stationary in line with the component even when HMR isn't running (though I may be missing something) so I'm going to throw out a PR to Vue for consideration. |
I refreshing each time.Very annoying. |
Hope it can be fixed soon. |
@sodatea hao dalao,when fix it? |
its so unfriendly |
Update: I need a better workaround...
I really can't disable keep-alive as it's critical to letting the browser know I've interacted with the page. And the runtime behavior of the app is completely different without keep alive. |
Any update ? |
Add cid comparison.
|
最好不要粘贴大段的代码,尽量把代码分段解释。 |
@sodatea Is it possible to fix this in Vue 2? Or at least for Vue 3? |
use transition。eg: |
My project use this way,But it does not work~ 😔 |
Version
13.3.0
Reproduction link
https://codesandbox.io/s/vyy3yokjj0
Steps to reproduce
1.modify the code in the script tag of the Hello component
2.the router-view component disappear from the page
3.we can find the component is activated with devtools
What is expected?
Hot reload normally
What is actually happening?
Have to refresh the page manually each time modify the code
The text was updated successfully, but these errors were encountered: