vue3 中响应式数据

一、非响应式数据

  1. 只有在 setup 函数中被 return 暴露的变量才可在模板中使用
  2. 只能用于初始化渲染视图,不可再次改变视图
<template>
  <div>{{ count }}</div>

  <!-- 不报错也不生效 -->
  <button @click="count++">count add</button>
</template>

<script>
export default {
  setup() {
    const count = 1;
    return { count };
  },
};
</script>

二、基础类型响应式数据(基础类型)

  1. 通过 ref()函数将基础类型数据包装成响应式数据
  2. 在 setup 函数中使用 ref() 包装的数据的值,需要通过.value 的方式
  3. 在模板中使用 ref() 包装的数据,直接使用,不使用.value 的方式
<template>
  <div>{{ count }}</div>
  <button @click="count++">count add 模板</button>
  <button @click="handleCountAdd()">count add setup</button>
</template>

<script>
import { ref } from "vue";

export default {
  setup() {
    const count = ref(1);
    console.log(count);

    const handleCountAdd = () => {
      count.value++;
    };
    return { count, handleCountAdd };
  },
};
</script>

三、对象类型响应式数据(对象和数组)

1. 通过 ref() 定义对象类型响应式数据

  1. 通过 ref()函数将对象类型数据包装成响应式数据
  2. 在 setup 函数中使用 ref() 包装的数据的值,需要通过.value 的方式
  3. 在模板中使用 ref() 包装的数据,直接使用,不使用.value
  4. ref()函数包装的对象数据是深层次的响应式数据(原理是当给 ref()传入对象时,实际上调用了 reactive()函数)
<template>
  <div>教师姓名:{{ teacher.name }}</div>
  <div>教师年龄:{{ teacher.age }}</div>
  <button @click="handleTeacherChange()">change teacher</button>
</template>

<script>
import { ref } from "vue";

export default {
  setup() {
    let teacher = ref({});
    setTimeout(() => {
      teacher.value = {
        name: "venus",
        age: 30,
      };
    }, 1000);

    const handleTeacherChange = () => {
      teacher.value = {
        name: "alias",
        age: 40,
      };

      teacher.value.name = "tom";
    };

    return { teacher, handleTeacherChange };
  },
};
</script>

2. 通过 reactive() 定义对象类型响应式数据

  1. reactive() 只能用于定义对象类型响应式数据,不能定义基础类型响应式数据
<template>
  <div>教师姓名:{{ state.teacher.name }}</div>
  <div>教师年龄:{{ state.teacher.age }}</div>
  <button @click="handleTeacherChange()">change teacher</button>
</template>

<script>
import { reactive } from "vue";

export default {
  setup() {
    const state = reactive({ teacher: {} });
    console.log(state);

    setTimeout(() => {
      state.teacher = {
        name: "venus",
        age: 30,
      };
    }, 1000);

    const handleTeacherChange = () => {
      state.teacher = {
        name: "alias",
        age: 40,
      };
      state.teacher.name = "tom";
    };

    return { state, handleTeacherChange };
  },
};
</script>
  1. toRefs() 将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref
    常用于批量解构 reactive()包装的响应式对象,将响应式对象的某些属性暴露给模板使用
<template>
  <div>教师姓名:{{ teacher.name }}</div>
  <div>教师年龄:{{ teacher.age }}</div>
  <button @click="handleTeacherChange()">change teacher</button>
</template>

<script>
import { reactive, toRefs } from "vue";

export default {
  setup() {
    const state = reactive({ teacher: {} });
    console.log(state);

    setTimeout(() => {
      state.teacher = {
        name: "venus",
        age: 30,
      };
    }, 1000);

    const handleTeacherChange = () => {
      state.teacher = {
        name: "alias",
        age: 40,
      };
      state.teacher.name = "tom";
    };

    return { ...toRefs(state), handleTeacherChange };
  },
};
</script>
  1. toRef() 是基于响应式对象(reactive 或者 ref 包装的对象)上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步
    常用于单独解构 reactive()包装的响应式对象,将响应式对象的某个属性暴露给模板使用,
    最常用的是 props 参数解构(由于 props 解构后会失去响应式功能,所以需要通过 toRef()解构需要的属性)
<template>
  <div>
    <div>{{ state.foo }}</div>
    <div>{{ fooRef }}</div>
  </div>
</template>

<script setup>
import { reactive, toRef } from "vue";
const state = reactive({
  foo: 1,
  bar: 2,
});

const fooRef = toRef(state, "foo");

// 更改该 ref 会更新源属性
fooRef.value++;
console.log(state.foo); // 2

// 更改源属性也会更新该 ref
state.foo++;
console.log(fooRef.value); // 3
</script>
  1. vue3 中 ref()、reactive() 包装的响应式数据是深层次的,解决了 vue2 中对象数据删除、增加属性和通过索引改变数组值视图不更新问题
<template>
  <div>
    <ul>
      <li v-for="item in names" :key="item">{{ item }}</li>
    </ul>
    <button @click="replaceNames">replaceNames</button>
  </div>
  <hr />
  <div>
    <div>
      <ul>
        <li>{{ userinfo.username }}</li>
        <li>{{ userinfo.password }}</li>
      </ul>
      <div><button @click="deleteInfo">deleteInfo</button></div>
      <div><button @click="addInfo">addInfo</button></div>
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";

const names = ref(["卡罗", "老蔫儿", "贼大胆"]);
function replaceNames() {
  names.value[0] = "卡梅利多";
}

const userinfo = ref({ username: "卡梅利多", password: "123456" });
function deleteInfo() {
  delete userinfo.value.username;
}
function addInfo() {
  userinfo.value.username = "卡梅利多";
}
</script>

四、定义数据的其他方式 --- shallowReactive()、shallowRef()、readonly()、shallowReadonly()、toRaw()、markRaw()

  1. shallowReactive() 是 reactive() 的浅层作用形式
    只有第一层是响应式数据
  2. shallowRef() 是 ref() 的浅层作用形式
    只有对第一次 .value 的访问是响应式的,常常用于对大型数据结构的性能优化或是与外部的状态管理系统集成
  3. readonly() 创建深层只读数据
    每一层都不可修改,常用于后代组件传参时,禁止子组件修改响应式数据(单向数据流)
  4. shallowReadonly() 是 readonly() 的浅层作用形式
    只有第一层不可修改,其他层可修改,且是响应式数据
  5. toRaw() 传入代理对象返回原始对象
    将响应式数据变成原始数据(暂时)
  6. markRaw() 传入代理对象返回原始对象,不可再次转变为响应式对象
    将响应式数据变成原始数据(永久)

五、响应式数据类型的判断 isReactive(), isReadonly(), isRef()

<template>
  <h1>App</h1>
  <div>{{ refCount }}</div>
  <div>{{ ReactiveCount.count }}</div>
  <div>{{ readonlyCount }}</div>
</template>

<script setup>
import { isReactive, isReadonly, isRef, reactive, readonly, ref } from 'vue'

const refCount = ref(1)
const ReactiveCount = reactive({
  count: 1
})
const readonlyCount = readonly({
  count: 1
})

console.log(isRef(refCount)) // true
console.log(isReactive(ReactiveCount)) // true
console.log(isReadonly(readonlyCount)) // true
</script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容