在 vuejs 中使用 v-for 时无限重复

Infinite repeated while using v-for in vuejs

我有一个 API 来获取书籍列表,在每本书中我都有作者 ID。 我还想通过另一个 API(获取作者)从该 ID 获取作者姓名,因此我使用 v-for 获取图书列表中的项目。我调用 getAuthor(authorId) 函数的每个项目,但它会无限重复。有谁知道原因是什么? 我的源代码:

export default {  
name: 'GetBooks',  
    data() {
        return {
            books: [],
            categories: [],
            author: [],
        };
    },
    created()  
    {  
        this.getBooks();  
    },  

methods: { 
    getBooks() {  
        BookServices.getBooks().then(response => {  
                this.books = response.data;  
                console.log(response.data);  
            })  
            .catch(e => {  
                console.log(e);  
            });  
    },  
    getAuthor(id) {  
        BookServices.getAuthor(id).then(response => {  
                this.author = response.data.name;
                console.log(response.data.name);  
            });
        return this.author;
    },  
}  

和:

<tbody>  
    <tr v-for="item in books" :key="item.id">  
        <td>{{ item.id }}</td>  
        <td>{{ item.name }}</td>  
        <td>{{ getAuthor(item.authorId) }}</td>  
        <td>{{ item.price }}</td>  
        <td>{{ item.year }}</td>   
        <td><input class='myclass' type='button' value='Detail'/></td>
    </tr>  
</tbody>  

问题是每次调用 getAuthor 都会触发模板重新呈现,这又会触发对 getAuthor 的新调用,因此会出现无限次调用。

我可以想到两个解决方案:

  1. td 中使用 v-once 指令。该指令阻止在初始渲染后进一步更新元素。
<td v-once> {{ getAuthor(item.authorId) }}</td>
  1. 在获取书籍数据时填充作者(也可以在 API 中完成)。

     getBooks() {  
         BookServices.getBooks().then(response => {  
                 this.books = response.data;
    
                 this.books = this.books.map(book => {
                     book["author"] = this.getAuthor(book.authorId)
                     return book
                 })  
    
             })  
             .catch(e => {  
                 console.log(e);  
             });  
     },  
    

然后,在模板中引用作者:

<tr v-for="item in books" :key="item.id">  
    <td>{{ item.id }}</td>  
    <td>{{ item.name }}</td>  
    <td>{{ item.author }}</td>  
    <td>{{ item.price }}</td>  
    <td>{{ item.year }}</td>   
    <td><input class='myclass' type='button' value='Detail'/></td>
</tr>  

模型获取方法应该决定何时以及如何获取作者,而不是标记。 (这是@IgorMoraru 的第二个好主意,已更正以正确处理作者的异步获取)。

这也修复了将书籍作者分配给视图实例的 OP 代码错误。

getBooks() {  
    BookServices.getBooks().then(response => {  
            this.books = response.data;  
            console.log(response.data);
            this.getAuthors();  
        })  
        .catch(e => {  
            console.log(e);  
        });  
},
getAuthors() {
  let promises = this.books.map(book => this.getAuthor(book));
  return Promise.all(promises);
},
getAuthor(book) {  // note the change: pass the book here, not the id
    BookServices.getAuthor(book.id).then(response => {  
            book.author = response.data.name;
            console.log(response.data.name);  
        });
    return this.author;
},  

保护(暂时)缺少作者的图书的标记...

    <td>{{ item.id }}</td>  
    <td>{{ item.name }}</td>  
    <td v-if="item.author">{{ item.author }}</td>
    <td v-else>fetching...</td>
    <td>{{ item.price }}</td>  
    <td>{{ item.year }}</td>