Vue 父組件循環使用refs調用子組件方法出現undefined的問題
1. 背景
最近前端項目遇到一個問題,我在父組件中使用了兩個相同的子組件child,分別設置ref
為add和update。其中A組件的功能是新增,也就是說在頁面上A頁面只有一個。而update組件是放在表格里的,表格中的每一行數據都有update組件。跟update組件並列還有一個刪除按鈕,每次刪除完都會重新獲取數據。
2.問題描述
界面第一次加載時我對表格的組件B進行操作的時候是沒問題的,但是當我刪除某一行的數據之后再點擊B組件,出現了update組件變為undefined的問題。
<el-table-column label="操作" min-width="100px">
<template slot-scope="scope">
<UpdateButton title="修改" @click.native="updateClick(scope.row)" size="mini"></UpdateButton>
<DeleteButton class="resource_pause_delete_button" @click.native="ruleDelete(scope.$index, scope.row)" />
<TimeSelectDialog ref="updateTime" title="修改暫停規則">
<update-button @click.native="updateData()" size="mini">
</update-button>
</TimeSelectDialog>
</template>
</el-table-column>
3.定位問題
因為add和update是相同的組件,所以我一開始認為是兩個組件的沖突。但是當我把add組件完全去掉之后,還是出現了undefined的問題。所以排除了add組件是干擾這個原因。
繼續猜想以為是組件渲染問題,於是我給update組件添加了nextTick和setTimeOut來讓組件渲染完成。但是這依然不起作用。
緊接着我看了下vue中關於ref的文檔。
當
v-for
用於元素或組件的時候,引用信息將是包含 DOM 節點或組件實例的數組。關於 ref 注冊時間的重要說明:因為 ref 本身是作為渲染結果被創建的,在初始渲染的時候你不能訪問它們 - 它們還不存在!
$refs
也不是響應式的,因此你不應該試圖用它在模板中做數據綁定。
我的組件用了element-UI的el-table組件,這個組件的內部肯定是使用了v-for循環的。於是我就把問題定位在v-for引起的數據綁定問題。
我把update組件從el-table中拿出來,放在表格之外。此時表格行內的按鈕只是調用update組件,並且每次調用的都是同一個組件。這次問題果然解決了。
4.總結
ref
本身是作為渲染結果被創建的,這句話應該是這樣理解的。如果在循環中使用了包含ref的組件,那么循環出來的就是ref組件渲染的結果。當數據改變需要重新循環的時候,因為ref並不是響應式的,這導致包含了ref組件的行就無法再被渲染出來,因此出現了undefined的問題。
反過來想,既然update組件是一個可重用的組件,那么我們每次都讓組件渲染其實並不是一個好的實現。實際上我的頁面中的update組件每次改變的只有數據。從這個角度思考,我的設計是不合理的。