如果子组件发生更改,如何重新渲染父组件

Posted

技术标签:

【中文标题】如果子组件发生更改,如何重新渲染父组件【英文标题】:How can I rerender parent component if child component changes 【发布时间】:2020-01-20 13:46:09 【问题描述】:

我正在开发一个书籍跟踪器应用程序,它可以跟踪您已阅读或将要阅读的书籍。我在服务器端使用 Vue.js 和 Express.js。共有三个列表(类别)。我正在尝试应用按钮更改书籍类别的功能(即从“当前阅读”到“已完成”)。有用。但我必须重新加载整个页面才能看到结果。 所以我有一个组件“我的书”,其中包括组件“书单”,我将“listType”作为道具传递并呈现所有三个列表。在“书单”组件中,我有 v-for 渲染所有书籍并使用“书”组件和书对象作为道具。 'book' 组件有用于更改类别的按钮。因此,当我按下其中一个按钮时,我可以在服务器端更改 listType 并更新数据库条目,甚至重新渲染“书”组件,但是如果不刷新整个列表,我就无法达到我的书从一个列表移动到另一个列表的地步页。

//mybooks 组件

<template> 
   <BookList listType="current" />
   <BookList listType="wantToRead" />
   <BookList listType="finished" />
</template>

//书单组件

<template> 
    <div v-for="bookElement in bookList" :key="bookElement.id">
      <Book :book="bookElement" />
    </div>
</template>

<script> 
export default 
  data() 
    return 
      bookList: []
    ;
  ,
  components: 
    Book
  ,
  props: ["listType"],
  watch: 
    "$route.query.searchDB": 
      //once a query string search value changes, get list of books from server
      immediate: true,
      async handler(value) 
        const list = (await BooksService.index(value)).data;

        //filter books by categories
        this.bookList = list.filter(element => 
          return element.listType === this.listType;
        );
      
    
  
</script>

// 图书组件

//template to render author, title etc
//and button for example
<button @click="changeTo('current', book.id)">Change to current</button>

<script>
import BooksService from "@/services/BooksService";
export default 
  data() 
    return 
      isCurrent: false,
      isLater: false,
      isFinished: false
    ;
  ,
  props: ["book"],
  mounted() 
    if (this.book.listType === "current") 
      this.isCurrent = true;
     else if (this.book.listType === "finished") 
      this.isFinished = true;
     else this.isLater = true;
  ,
  methods: 

    async changeTo(list) 
      this.book.listType = list;

      try 
        await BooksService.put(this.book);
       catch (err) 
        this.error = err;
            
    
  
;
</script>

【问题讨论】:

通常,如果您希望子组件的逻辑影响父组件,那么您需要将该逻辑上移到父组件。然后,您可以作为道具或emit 传递对它的引用。否则,即使孩子的状态发生变化,您的父组件也不会受到其孩子正在做什么的影响。 【参考方案1】:

您在正确的轨道上,但您不了解 Vue 希望处理数据的方式。

你做对了

你的父组件 booklist 通过 prop v-bind :book 将数据传递给子组件 Book

现在需要做什么

Book 发生变化时,它需要执行诸如$emit('bookChanged', book) 之类的发射事件,以便任何父组件都知道其子组件中发生了某些事情并需要做出反应。所以在我的例子中你的代码看起来像

<Book :book="bookElement" @bookChanged="RefreshMe_Method"  />

此时 RefreshMe_Method 可以做几件事之一,这个简单的方法是简单地更新传递给 Prop :book 的数据,或者另一个更强力的选项是调用 this.$forceUpdate(); 但我确信只是更新数据会自动刷新你想要的数据。

如何处理数据

    家长将数据传递给孩子(想想第一天的学校午餐)。 Child 显示数据、改变数据(本地副本而不是 Prop)或执行一些特殊操作。 (扔掉蔬菜) 孩子为此感到非常自豪,它想让每个人都知道所以它@98​​7654329@ 改变了。 所有父母都看到了这一点,并且可以从这一点开始做他们想做的事。 (将孩子接地并仅包装 Brocolli)

【讨论】:

感谢您的回答。但它不起作用。我在 Book 组件和 BookList 组件中执行 $emit 捕获它并使用方法,但是 this.$forceUpdate() 不会改变任何东西。然后我尝试对 BookList 和 MyBooks 组件($emit 并捕获它)做同样的事情并在那里尝试 forceUpdate,但效果不佳...... @NikitaSkopin 您是否正在分配数据以更新孩子的道具? forceUpdate 只会刷新渲染,如果数据相同则不会有变化。 是的,我在使用 forceUpdate 之前做过,但是做错了。所以最终我解决了我的问题。谢谢! @NikitaSkopin 如果此答案帮助您解决了问题,请将其标记为已回答。祝你编码好运!

以上是关于如果子组件发生更改,如何重新渲染父组件的主要内容,如果未能解决你的问题,请参考以下文章

如何在反应原生的子组件上重新渲染父组件?

子组件不会重新渲染,但父组件会重新渲染。如何让子组件重新渲染?

当父组件在 Next.js 应用程序中更新其道具时重新渲染 React 子组件

如何在其他组件的状态更改时重新渲染 DOM

vue的开发工具插件确实好用,能看到各个变量的变化,父子组件传值是数据驱动,如果子组件的值没有成功传回来,会导致父组件的值后面事件再触发的时候不变化,如果父组件里的值没有变化,就不会重新传给子组件的p

state 用作组件中的 props,状态更改不会重新渲染组件