飞道的博客

Vue3.0学习 - 第八节,toRaw 和 reactive、ref,markRaw

319人阅读  评论(0)

reactive的一些补充,先看代码:


  
  1. <template>
  2. <div>
  3. <p>{{state}} </p>
  4. <button @click="fn">reactive </button>
  5. </div>
  6. </template>
  7. <script>
  8. import { reactive, toRaw } from "vue";
  9. export default {
  10. setup() {
  11. let obj = { name: "zs", age: 18 };
  12. let state = reactive(obj);
  13. function fn() {
  14. obj.name = "ls";
  15. console.log( "obj", obj);
  16. console.log( "state", state);
  17. }
  18. return { state, fn };
  19. },
  20. };
  21. </script>

页面打印效果:

我们可以看出改变obj数据吗,state也会跟着改变,但是UI界面却没有刷新,这个是什么问题呢?

我们先看 obj 和 state 的关系

obj和state:引用关系,state的本质是一个Proxy对象,在这个Proxy对象中引用了obj

  • 直接修改obj是无法触发UI界面更新的

  • 只有通过包装之后的对象来修改,才会触发界面更新

通过改变包装之后的state改变数据:


  
  1. <template>
  2. <div>
  3. <p>{{state}} </p>
  4. <button @click="fn">reactive </button>
  5. </div>
  6. </template>
  7. <script>
  8. import { reactive, toRaw } from "vue";
  9. export default {
  10. setup() {
  11. let obj = { name: "zs", age: 18 };
  12. let state = reactive(obj);
  13. function fn() {
  14. // obj.name = "ls";
  15. state.name = "woshinibaba";
  16. console.log( "obj", obj);
  17. console.log( "state", state);
  18. }
  19. return { state, fn };
  20. },
  21. };
  22. </script>

效果如下:我们可以看到 obj 和 state 数据都发生了改变,UI界面也更新了

 

使用toRaw:


  
  1. <template>
  2. <div>
  3. <p>{{state}} </p>
  4. <button @click="fn">reactive </button>
  5. </div>
  6. </template>
  7. <script>
  8. import { reactive, toRaw } from "vue";
  9. export default {
  10. setup() {
  11. let obj = { name: "zs", age: 18 };
  12. let state = reactive(obj);
  13. let obj2 = toRaw(state)
  14. console.log( "obj==obj2",obj===obj2)
  15. function fn() {
  16. // obj.name = "ls";
  17. // state.name = "woshinibaba";
  18. console.log( "obj", obj);
  19. console.log( "state", state);
  20. console.log( "obj2", obj2);
  21. }
  22. return { state, fn };
  23. },
  24. };
  25. </script>

我们可以看出 obj2 obj是一样的,也就是说通过toRaw拿到了state的原始数据 obj

我们修改obj2的值:


  
  1. <template>
  2. <div>
  3. <p>{{state}} </p>
  4. <button @click="fn">reactive </button>
  5. </div>
  6. </template>
  7. <script>
  8. import { reactive, toRaw } from "vue";
  9. export default {
  10. setup() {
  11. let obj = { name: "zs", age: 18 };
  12. let state = reactive(obj);
  13. let obj2 = toRaw(state);
  14. console.log( "obj==obj2", obj === obj2);
  15. function fn() {
  16. // obj.name = "ls";
  17. // state.name = "woshinibaba";
  18. obj2.name = "woshinidie";
  19. console.log( "obj", obj);
  20. console.log( "state", state);
  21. console.log( "obj2", obj2);
  22. }
  23. return { state, fn };
  24. },
  25. };
  26. </script>

效果:我们可以看到通过修改 obj2 会同步修改 obj 和 state ,但是UI界面没有更新

我们可以发现    obj2通过toRaw拿到state的原始数据,进行修改,就不会更新界面。

总结:如果我们想修改 state 的内容而又不想引起UI界面的更新,就只需要用 toRaw 取出它的 “源值” 进行修改就行了。总之, toRaw 是一个用来优化资源加载的方案。

我们看一下 ref 的 toRaw:

我们回顾一下 ref 的本质是什么:

ref本质:reactive    ref(obj) —> reactive({value:obj})

ref toRaw代码如下:


  
  1. <template>
  2. <div>
  3. <p>{{oref}} </p>
  4. <button @click="fn">reactive </button>
  5. </div>
  6. </template>
  7. <script>
  8. import { ref, toRaw } from "vue";
  9. export default {
  10. setup() {
  11. let obj3 = { name: "狗子", age: 88 };
  12. let oref = ref(obj3);
  13. let toref = toRaw(oref);
  14. function fn() {
  15. console.log( "obj3", obj3);
  16. console.log( "oref", oref);
  17. console.log( "toref", toref);
  18. }
  19. return { oref, fn };
  20. },
  21. };
  22. </script>

效果:我们可以看出 和 reactive不一样,这是为什么呢?

根据 ref 的本质可以看出 我们应该去拿 .value ,我们再试一下


  
  1. <template>
  2. <div>
  3. <p>{{oref}} </p>
  4. <button @click="fn">reactive </button>
  5. </div>
  6. </template>
  7. <script>
  8. import { ref, toRaw } from "vue";
  9. export default {
  10. setup() {
  11. let obj3 = { name: "狗子", age: 88 };
  12. let oref = ref(obj3);
  13. let toref = toRaw(oref.value);
  14. console.log( "obj3 == toref",obj3 == toref)
  15. function fn() {
  16. console.log( "obj3", obj3);
  17. console.log( "oref", oref);
  18. console.log( "toref", toref);
  19. }
  20. return { oref, fn };
  21. },
  22. };
  23. </script>

我们需要注意的几个点:

  • 如果想通过toRaw拿到ref类型的原始数据(创建时传入的那个数据)
  • 那么就必须明确告诉toRaw方法,要获取的还是 .value 的值
  • 因为经过vue处理之后, .value 中保存的才是当初创建时传入的那个原始数据

 

下面我们来修改一下 ref 的toRaw :


  
  1. <template>
  2. <div>
  3. <p>{{oref}} </p>
  4. <button @click="fn">reactive </button>
  5. </div>
  6. </template>
  7. <script>
  8. import { ref, toRaw } from "vue";
  9. export default {
  10. setup() {
  11. let obj3 = { name: "狗子", age: 88 };
  12. let oref = ref(obj3);
  13. let toref = toRaw(oref.value);
  14. console.log( "obj3 == toref", obj3 == toref);
  15. function fn() {
  16. console.log( "obj3", obj3);
  17. console.log( "oref", oref);
  18. toref.name = "我是你爹";
  19. console.log( "toref", toref);
  20. }
  21. return { oref, fn };
  22. },
  23. };
  24. </script>

我们可以看出,修改toref 会修改 oref 的数据,obj3没有变化,因为我们拿到的是oref的 .value,   我们可以看到界面没有更新

此时,和 reactive 的 toRaw 效果就完全一致了

总结:

 ref/reactive 数据类型特点:

每次修改都会被追踪,都会更新UI界面,但是这样其实是非常消耗性能的

所以如果我们有一些操作不需要被追踪,不需要更新UI界面,那么这个时候,我们就可以通过toRaw方法拿到它的原始数据

对原始数据进行修改,这样就不会被追踪,这样就不会更新UI界面,这样性能就变好了

 

附录全部代码:


  
  1. <template>
  2. <div>
  3. <p>{{state}} </p>
  4. <button @click="myfun">changeRaw </button>
  5. <hr>
  6. <p>{{oref}} </p>
  7. <button @click="fn">ref </button>
  8. </div>
  9. </template>
  10. <script>
  11. import { ref, toRaw, reactive } from "vue";
  12. export default {
  13. name: "App",
  14. setup() {
  15. let obj = {
  16. name: "csl",
  17. age: 18,
  18. };
  19. /*
  20. ref/reactive 数据类型特点:
  21. 每次修改都会被追踪,都会更新UI界面,但是这样其实是非常消耗性能的
  22. 所以如果我们有一些操作不需要被追踪,不需要更新UI界面,那么这个时候,我们就可以通过toRaw方法拿到它的原始数据
  23. 对原始数据进行修改,这样就不会被追踪,这样就不会更新UI界面,这样性能就变好了
  24. */
  25. let state = reactive(obj);
  26. // state 和 obj 关系 引用关系 ,state的本质是一个Proxy对象,在这个Proxy对象中引用了obj
  27. let obj2 = toRaw(state);
  28. // console.log("obj==state", obj === state, obj === obj2); //false true
  29. function myfun() {
  30. // 如果直接修改obj是无法触发界面更新的
  31. // 只有通过包装之后的对象来修改,才会触发界面更新
  32. // obj.name = "zsssss"
  33. console.log(obj) //{name: "zsssss", age: 18}
  34. // state.name = "zsss";
  35. // console.log(state);//{name: "zsssss", age: 18}
  36. obj2.name = "zssss";
  37. console.log( "obj2", obj2);
  38. console.log(state);
  39. }
  40. let obj3 = { name: "狗子", age: 88 };
  41. /*
  42. 1、ref本质:reactive
  43. ref(obj) ——> reactive({value:obj})
  44. * */
  45. let oref = ref(obj3);
  46. // 注意点:如果想通过toRaw拿到ref类型的原始数据(创建时传入的那个数据)
  47. // 那么就必须明确告诉toRaw方法,要获取的还是 .value 的值
  48. // 因为经过vue处理之后, .value 中保存的才是当初创建时传入的那个原始数据
  49. // let toref = toRaw(oref)
  50. let toref = toRaw(oref.value)
  51. function fn(){
  52. console.log( "obj3",obj3)
  53. console.log( "oref",oref)
  54. toref.name = "lllkkkk"
  55. console.log( "toref",toref)
  56. }
  57. return {
  58. state,
  59. myfun,
  60. oref,
  61. fn
  62. };
  63. },
  64. };
  65. </script>

markRaw

有的时候,我们希望某些数据是无法被改变的。

markRaw

显式标记一个 对象 (不能是简单类型) 为“永远不会转为响应式代理”,函数返回这个对象本身。


  
  1. const foo = markRaw({})
  2. console.log(isReactive(reactive(foo))) // false
  3. // 如果被 markRaw 标记了,即使在响应式对象中作属性,也依然不是响应式的
  4. const bar = reactive({ foo })
  5. console.log(isReactive(bar.foo)) // false

  
  1. <template>
  2. <div>
  3. <p>{{ state }} </p>
  4. <button @click="fun">click </button>
  5. </div>
  6. </template>
  7. <script>
  8. import { reactive, markRaw } from "vue";
  9. export default {
  10. setup() {
  11. let obj = { name: "我是你爹", age: 22 };
  12. obj = markRaw(obj)
  13. let state = reactive(obj);
  14. function fun() {
  15. state.name = "叫爸爸";
  16. console.log(state)
  17. }
  18. return { state, fun };
  19. },
  20. methods: {},
  21. };
  22. </script>

 


转载:https://blog.csdn.net/csl125/article/details/116235214
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场