Vue中的无限更新循环
Posted
技术标签:
【中文标题】Vue中的无限更新循环【英文标题】:infinite update loop in Vue 【发布时间】:2018-07-17 21:17:12 【问题描述】:我正在尝试编写自定义组件。并希望我可以这样使用它
let app = new Vue(
el:'#app',
template:`
<tab>
<tab-item name='1'>
<h1> This is tab item 1</h1>
</tab-item>
<tab-item name='2'>
<h2> This is tab item 2</h2>
</tab-item>
</tab>`,
components:
tab,
tabItem
)
在您单击按钮之前一切正常。我从控制台收到错误:
[Vue warn]: You may have an infinite update loop in a component render function.
found in
---> <Tab>
<Root>
我尝试了很多方法来解决这个问题,但是,失败总是赢得调试比赛。
我该如何解决这个问题?
这是我的代码:
let tabItem =
props:
name:
type: String,
required: true
,
render(h)
let head = this.$slots.head || ''
let body = this.$slots.default
let tail = this.$slots.tail || ''
return h('div', [
h('div', head),
h('div', body),
h('div', tail)])
let tab =
data()
return
items:'',
currentView:0
,
methods:
handleTabClick(item)
return ()=>
let index = this.items.indexOf(item)
this.currentView = this.items[index]
,
extractProps(vnode)
return vnode.componentOptions.propsData
,
render(h)
this.items = this.$slots.default.filter( node =>
return /tab-item/.test(node.tag)
)
let headers = this.items.map( item =>
let name = this.extractProps(item).name
return h('button',
on:
click: this.handleTabClick(item)
, name)
)
let head = h('div', headers)
this.currentView = this.items[0]
return h('div',[head, this.currentView])
或者任何其他方式来实现这个组件?
非常感谢你帮助我摆脱困境。
感谢您的回复我的朋友。我很确定我从控制台收到了一个无限循环错误,并且我的代码没有按预期工作。我不认为使用vnode
也是实现这个组件的好方法。但是,这是我能想到的最佳解决方案。
这个组件——tab
应该检测到它的名字为tabItem
的子组件,它也是一个组件。而tab
可以从tabItem
中提取一些数据。在我的例子中,tab
将提取tabItemn
的name
属性,用于生成切换内容的按钮。点击按钮可以切换到相关内容,即tabItem
的正文。在我的代码中,它是currenView
。
像一个著名的UI库Element,它的tab
组件可以这样使用:
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="User" name="first">User</el-tab-pane>
<el-tab-pane label="Config" name="second">Config</el-tab-pane>
<el-tab-pane label="Role" name="third">Role</el-tab-pane>
<el-tab-pane label="Task" name="fourth">Task</el-tab-pane>
</el-tabs>
我需要实现一个这样的组件,但我的会更简单。为了学习如何做,我阅读了它的源代码。也许没有过滤子组件的好方法。在源代码中,他们使用它来过滤el-tab-pane
组件:
addPanes(item)
const index = this.$slots.default.filter(item =>
return item.elm.nodeType === 1 && /\bel-tab-pane\b/.test(item.elm.className);
).indexOf(item.$vnode);
this.panes.splice(index, 0, item);
Source Code
我知道我可以使用$children
来访问它的子组件,但是这样做并不能保证子组件的顺序,这不是我想要的。因为切换按钮的顺序很重要。文档中不包含有关 vnode
的详细消息。我需要阅读源代码。
因此,在阅读了 Vue 的源代码之后,我这样编写了我的代码,然后我遇到了问题。
我终于没有解决这个错误并承认使用这种罕见的代码很糟糕。但我不知道其他解决方案。所以我需要你们的帮助。
谢谢。
【问题讨论】:
肯定你有一个无限循环。你的渲染函数总是调用它自己。你想做什么,为什么需要槽、vnode 和手动渲染函数(这些函数很奇特、可能很复杂并且很少使用)? @bbsimonbb 是的,我也认为这很糟糕,但我找不到其他方法。我添加更多信息。 【参考方案1】:You shouldn't change your data in render function,这是错误的
this.items = this.$slots.default.filter( node =>
return /tab-item/.test(node.tag)
)
因为它会继续重新渲染,这里是您的代码的一个工作示例,我只是从数据中删除了items
属性并添加了新的items
计算属性,该属性返回tab-item
s 节点。
let tab =
data()
return
currentView:0
,
methods:
handleTabClick(item)
return ()=>
let index = this.items.indexOf(item)
this.currentView = this.items[index]
,
extractProps(vnode)
return vnode.componentOptions.propsData
,
computed:
items()
return this.$slots.default.filter( node =>
return /tab-item/.test(node.tag)
)
,
render(h)
let headers = this.items.map( item =>
let name = this.extractProps(item).name
return h('button',
on:
click: this.handleTabClick(item)
, name)
)
let head = h('div', headers)
this.currentView = this.items[0]
return h('div',[head, this.currentView])
let tabItem =
name:"tab-item",
props:
name:
type: String,
required: true
,
render(h)
let head = this.$slots.head || ''
let body = this.$slots.default
let tail = this.$slots.tail || ''
return h('div', [[
h('div', head),
h('div', body),
h('div', tail)]])
let app = new Vue(
el:'#app',
template:`
<tab>
<tab-item name='1'>
<h1> This is tab item 1</h1>
</tab-item>
<tab-item name='2'>
<h2> This is tab item 2</h2>
</tab-item>
</tab>`,
components:
tab,
tabItem
)
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.min.js"></script>
<div id="app"></div>
【讨论】:
谢谢老兄。您的解决方案确实停止了来自控制台的警告。但是,它无法按预期运行。单击按钮时,内容没有切换。但是你找到了解决它的关键。非常感谢。 点击按钮时改变内容,需要改变this.currentView = this.items[0]
这一行,改变索引动态选择需要的内容,以上是关于Vue中的无限更新循环的主要内容,如果未能解决你的问题,请参考以下文章