reactdom.render props不更新_【Vue原理】Props 源码版

↑点击上方 “神仙朱” 一起研究Vue源码吧

6b26b1976a956b328b8c0d92e8632587.png

专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧

研究基于 Vue版本2.5.17

今天记录 Props 源码流程,哎,这东西,就算是研究过了,也真是会随着时间慢慢忘记的。

幸好我做了详细的文章,忘记了什么的,回忆起来必然是很快的。

好的,回到正题,Props

请你在读这篇之前,先去看看我的白话版

【Vue原理】Props - 白话版

在上面这篇文章中,也已经清楚地解决了一个问题

父组件 如何 把数据 当做 props 传给子组件

所以今天,我们只需记录 Props 的处理流程源码即可

5638b626d6d0c5b0d772eb7b2ae4aa9d.png

初始化

在创建Vue实例的过程中,会调用 initState 处理options,比如 props,computed,watch 等

只要你 new Vue 创建实例之后,很快就会处理options

function Vue(){
   ... 其他处理
   initState(this)

   ...解析模板,生成DOM 插入页面

}

function initState(vm) {    

    var opts = vm.$options;    

    if (opts.props) {

       initProps(vm, opts.props);
   }

    ... 处理 computed,watch,methods 等其他options

}

5638b626d6d0c5b0d772eb7b2ae4aa9d.png

initProps

你看到处理 Props ,主要用到了一个方法 initProps,他就是本场的焦点了,让我们来采访下源码本码

function initProps(vm, propsOpt) {    
  // 这是父组件给子组件传入的 props 的具体值

  var propsData = vm.$options.propsData || {};    

   var props = vm._props = {};    

   for (var key in propsOpt){        

       // 给 props 的 key 设置 响应式

      defineReactive(props, key,  propsData[key]);        

       if (! (key in vm)) {            

           // 转接访问,访问 vm 属性,转到访问 vm._props 属性
          proxy(vm, "_props", key);
      }
  }
}

上面的代码主要做了三件事

1、遍历 props

2、给 props 设置响应式

3、给 props 设置代理

我们主要讲两件事

1给 props 设置响应式

defineReactive(props, key,  propsData[key])

defineReactive 在这里就不给太多源码了,你只需要记住他就是给 props 设置响应式的

function defineReactive(obj, key) {    

    Object.defineProperty(obj, key, {  

       get() { ...依赖收集 },
       set(newVal) { ....依赖更新 }
   });
}

如果你想了解响应式,就可以看我这篇文章

【Vue原理】响应式原理 - 白话版

Props 设置响应式,也是旨在数据改变时动态更新。

怎么设置响应式吗?看这里

【Vue原理】依赖收集 - 源码版之基本数据类型

【Vue原理】依赖收集 - 源码版之引用数据类型

数据是直接从 父组件上传过来的,没有进行拷贝等处理,原样传过来

怎么传的?也可以看

【Vue原理】Props - 白话版

如果props 是基本类型

在 子组件实例上设置这个 props 属性为响应式,跟 data 本质一样,作用是监听 props 修改

如果 props 是对象

也会在 子组件实例上 设置这个 props 属性为响应式,作用也是监听 props 修改

但是!

【不会递归对象】给对象内所有属性设置响应式,因为该对象【已经在父组件中】完成响应式设置了

也就是说

如果你在 子组件中直接修改 props 对象内的数据,父组件也会跟着修改

在记录的途中,我发现了一个问题,发现没有想象中的那么简单,所以现在郑重记录

1ee2fc8070e268ecbaa97e2781d3eb84.png当 父组件数据 改变,子组件怎么更新?

分类型的,说得比较详细,可能有点绕?

1 如果是基本类型,是这个流程

父组件数据改变,只会把新的数据传给子组件

子组件拿到新数据,就会直接替换到原来的 props

替换就是直接等哈,看下源码,重要语句标红

updateChildComponent 是子组件内部更新时会调用到的一个函数,这是其中更新 props 的一个片段

function updateChildComponent(

   vm, propsData

) {    

    if (propsData && vm.$options.props) {        

      // 保存 props 的地方,用于访问转接,具体看文章下面

     var props = vm._props;        

      // 所有子组件上设置的 props 的 key

     var propKeys = vm.$options._propKeys || [];        

      for (var i = 0; i < propKeys.length; i++) {            

        var key = propKeys[i];

       props[key] = propsData[key]
     }
    vm.$options.propsData = propsData;
  }
}

而 props 在子组件中也是响应式的,【直接 等号 替换】导致触发 set,set 再通知 子组件完成更新

127401602f79945e3c5eb6ab17661737.pngb7ea2bd9a62a42712ae082e18e92de7a.png

数据是 基本类型,然后设置定时器修改数据

watcher1 是父组件,watcher2 是子组件

父组件内的 data  num 通知 watcher1 更新

子组件内的 props  child_num 通知 watcher2 更新

92fa5f7c3c196cc0b9682c7e76d2d89a.png

2如果是对象,是这个流程

条件

父组件传 对象 给 子组件,并且父子组件 页面都使用到了这个数据

结果

那么这个对象,会收集到 父子组件的 watcher

所以

当 对象内部被修改的时候,会通知到 父和子 更新。

例子

父组件设置  obj 对象,并传给子组件

189e42633f1f333a2433d16bb9430e34.pngcb1573a924ca8109de5e0f98b1ca5163.png

定时修改父组件数据 obj.name ,可以看到是 obj.name 通知 父子更新

09406c71220663d6b64d70ca91348cfa.png

当然,如果对象被整个替换了,而不是修改内部,那么跟 基本类型一样

区别是什么?

1、基本类型是,子组件内部 props 通知 子组件更新的

2、引用类型是,父组件的数据 data 通知 子组件更新的

2给 props 设置代理

在白话版中,我已经说得很清楚了, Props 有个移花接木的暗箱操作,就是访问转移

Data 也是这么做的

【Vue原理】代理 Data - 源码版

你在项目中,会使用 this.xxx去访问 props,props 已经当成了 实例的属性,所以可以直接访问

但是其实你访问的是 【this._props.xxx】

为什么 Vue 要这么弄,目的就是为了方便开发啊,让我们直接简短了相关代码

而 React,访问 props,还要 this.props.xxxx,写这么长,不嫌麻烦吗?

那么,是怎么设置代理的呢,就是下面这行

proxy(vm, "_props", key);

proxy 是什么也不要急,瓜就在下面,拿凳坐好

function proxy(

    target, sourceKey, key

) {    

  Object.defineProperty(target, key, {

     get() {            

          return this[sourceKey][key]

     },

     set(val) {            

          this[sourceKey][key] = val;

     }
 });
}

这段代码做了2 个事

1、使用 props 在 vm 上占位,使得可以通过 vm.xxx 的形式访问到 props 

2、设置 [Object.defineProperty] 的 get 和 set ,间接获取和赋值 vm._props

所有访问赋值 props,转接到 vm._props 上,直观如下图

6743a5a47c8c80aaeddda83571e9664c.png

上个实例,方便大家看

9dcc0d701a826f6e2934a3139c6b9897.png

5638b626d6d0c5b0d772eb7b2ae4aa9d.png

最后

鉴于本人能力有限,难免会有疏漏的地方,请大家多多包涵,旨在交流,如果有任何描述不当的地方,欢迎后台联系本人,领取红包

如果你能转发一下,就更好啦,技术人交流 只用文章

长按关注>>>

盘它 7d4c4ba59459d58abf656f3e220296ff.png 72630b2bdb14a48b5b12ca3c4b2ed7dd.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值