vue如何在组件属性变化时就初始化状态?

code_sir
  • 456

比如组件有一个loading状态,每次父组件P更改子组件S的属性时,我希望子组件的loading是true,等数据请求完了再设置成false。

每次属性变化时,该如何初始化组件内部的状态值呢?
(不要告诉我如何实现这样的loading需求啊,我是在问vue的生命周期对状态的控制)

也就是:
父组件切换子组件的状态,子组件的状态每次都有个初始化的动作。

回复
阅读 1k
8 个回答

有 watch 呀,在子组件中的 watch 监听父组件对你的更新即可。

这是送分题吗?


已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

父级直接使用 props 传入 loading 就可以了,然后子组件按照传入的 loading 展示加载效果。
当然你也可以单纯的 watch 传入的 data 是否有值来判断是否需要展示加载效果,但是我觉得由父级来控制会更好(请求api的层级来控制)。
一段伪代码

<body>
  <child-component :loading="loading" />
</body>

<script>
  Vue.component("child-component", {
    props:['loading'],
    template: "<a-spin :spinning='loading'><span>child-component</span></a-spin >"
  });

  new Vue({
    el: "component-demo",
    data: {
      loading: false
    },
    methods:{
      loadData(){
        this.loading = true
        getAction(xxx).then(()=>(this.loading = false))
      }
    }
  });
</script>
已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

题主说了是要用生命周期去解决,那我建议是你在父组件异步的时候,
先将传输的属性list清空,通过updated来检测。但是有弊端就是只要list为数组且为空,那么loading一直存在,或者你的list可以接受多个类型,当不为数组时默认判断ajax失败。

总体来说,上面一些答题者用watch的Props的思路才是比较正确的思路,一般业务开发都会这样搞。

又或者用computed,如果用vue的生命周期做,我十分不推荐。
下面是用updated去做的

<body>
  <div>{{loading}}</div>
</body>
<script>
export default {
   name:'childComponent',
   props:{
      list:{
         type:Array,
         default:()=>([])
      }
   },
   data(){
      return {
          loading:false
      }
   },
   updated(){
     if(this.list.length === 0){
         this.loading = true
     }else{
         this.loading = false
     }
   }
</script>

我可以理解为是每次父组件进行操作后需要重置子组件吗?如果是这样的话,可以给子组件加个key,父组件每次操作就去改变keykey的值可以使用时间戳之类的,比如:

<template>
  <div>
  <Demo :key="id"></Demo>
  <button @click="refresh">refresh</button>
  </div>
</template>
<script>
  import Demo from './Demo'
  export default {
    data () {
      return {
        id: new Date().getTime()
      }
    },
    methods: {
       refresh: function () {
        this.id = new Date().getTime()
      }
    },
    components: {
      Demo
    }
  }
</script>
已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

我猜你的目前的问题是不是这样

  • 初始化切换子组件(第一次进入),能检测到数据有变化
  • 第二次进行切换子组件的时候,子组件的各个生命周期都没变化

关于这个问题解决思路的话,使用watch是最好的

其实你第一次初始化子组件的时候,他会执行各个created mounted 之类的,但是你第二次切换的时候,是不会执行的,因为组件已被创建了。

你可以尝试在使用 子组件的地方加个 v-if, 这样你子组件切换的使用通过一个值控制他,
image.png

我为什么感觉有点偏题了呢?

image.png

那么告诉我,Vue的声明周期有什么?

image.png

看上去比较像的就是 update 的钩子函数。那么我们只需要在里面修改自组件的loading为true就可以了。

image.png

这里你又会问我,那我这么判断是我要的更新了? this.$options.propsData可以获取到你传入的对象,你可以在mounted或者什么地方拦截一下,然后维护一下props传入的内容。搭配钩子使用。

当然都到这一步了,你也可以拿到props传入的内容去动态 vm.$watch( expOrFn, callback, [options] )

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

假设你这个改动的组件属性是 id
父组件P:

<S :id="id"></S>

子组件S:

<template>
  <div v-loading="loading">

  </div>
</template>

<script>
export default {
  data () {
    return {
      loading: false,
    }
  },
  created() {

  },
  watch: {
    id: function(){
      this.loading = true;
      axios.get('/user?id=' + this.id).then((response)=> {
        console.log(response);
        this.loading = false;
      })
    }
  }
}
</script>

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏