Vue3の応答性

1. レスポンシブの基本

1.1 応答性の高いオブジェクトまたは配列 (配列は本質的にオブジェクトです) を作成するにはどうすればよいですか? (通常のオブジェクトを応答性にするにはどうすればよいですか?)

vuereactive()関数を使用します。

import {
    
    reactive} from 'vue';


//这行代码可以放在<script setup> 或者在 setup() 函数中
const state = reactive({
    
    count : 0});

stateレスポンシブオブジェクトです。

1.2 このレスポンシブ オブジェクトの使用方法は?

のトップレベルのインポートと変数宣言は、同じテンプレート内<script setup>で直接使用できます。

<template>
<!-- 直接使用state.count -->
<div>当前的值:{
    
    {
    
    state.count}}</div>
</template>

<script setup>

import {
    
    reactive} from "vue";

const state = reactive({
    
    count:0});

//延迟5秒后,count数加1
setTimeout(()=>{
    
    
  state.count +=1;//直接使用
},5000)

</script>

1.3 共通オブジェクトのディープ属性もオブジェクトまたは配列である場合、この共通オブジェクトが応答オブジェクトを生成すると、この共通オブジェクトのディープ オブジェクトまたは配列は応答しますか?

reactive()作成されたリアクティブ オブジェクトはすべてディープです。ディープ オブジェクトまたは配列もリアクティブであり、その変更を監視できます。リアクティブ オブジェクト内のオブジェクトは依然としてプロキシです。

<template>
<!-- 直接使用state.count -->
<div>当前的值:{
    
    {
    
    state.count}}</div>
<div>当前的值:{
    
    {
    
    state.taskInfo.status}}</div>
</template>

<script setup>

import {
    
    reactive} from "vue";

const state = reactive({
    
    count:0,taskInfo:{
    
    status:"未开始"}});

state.taskInfo= {
    
    status:"暂停中"};//赋值新对象后,state.taskInfo属性还是响应式的

setTimeout(()=>{
    
    
  state.count +=1;
  state.taskInfo.status ="进行中";
},5000)

</script>

1.4 通常のオブジェクトのプロパティ値を変更した後、それらはインターフェイス上に同時に表示されますか?

いいえ、元のオブジェクトは通常のオブジェクトです。生成reactive()されるのはプロキシ オブジェクトです。元のオブジェクトを包むオブジェクトがあることがわかります。このオブジェクトを元のオブジェクトのパッケージング オブジェクトと呼びます。これにより応答性が実現されます。梱包対象です。したがって、通常のオブジェクトのプロパティ値の変更は更新をトリガーしません。

import {
    
    reactive} from "vue";

const obj = {
    
    count:0,taskInfo:{
    
    status:"未开始"},username:['张三','李四']};

const state = reactive(obj);

//obj.count = 15;如果在这里改值的话 界面上显示的值直接就变成15了 ??

setTimeout(()=>{
    
    
  obj.count = 5;//改变原始对象的属性值
  obj.taskInfo = {
    
    status:"暂停中"}
  obj.username =['马冬梅']
  console.log(obj.count)
  console.log(obj.taskInfo)
  console.log(obj.username)
  console.log(state.count)//响应式对象的值也变了,输出的是5,但是不会触发DOM刷新,界面上显示还是原来的值 0,下同
  console.log(state.taskInfo)
  console.log(state.username)
},5000)

1.5reactive()関数にはいくつかの制限があります

  1. プリミティブ型ではなく、オブジェクト型に対してのみ有効です。
  2. リアクティブ オブジェクトへの参照を常に保持しておく必要があります。新しい値が割り当てられると、リアクティブ接続は古い参照から切断されます。

1.6 プリミティブ型の場合、どうすれば応答型に変換できますか?

ref()任意の値 type を作成できる反応性を使用してrefref()関数は受信値をvalue属性を持つrefオブジェクトにラップします。value属性の値は受信値です。受信した値がオブジェクトの場合、それreactive()を自動的に変換するために呼び出されます.valueref応答性を損なうことなく、任意の値への参照を作成し、それらの参照を渡すことができます。これは、このオブジェクトが渡されるためですref

import {
    
    ref} from "vue";

const btnState = ref(0)
setTimeout(()=>{
    
    
  btnState.value = 1
},5000)

1.7 このオブジェクトの使用方法はref?

これらがテンプレート内のトップレベルの属性である場合、ラップを解除する必要はなく、自動的にラップが解除されます。それがトップレベルの属性でない場合はそうではありません。分解することで、それらをトップレベルのプロパティに変えることができます。

<template>
<!-- 必须得加上value 不然显示的是[Obejct Object]1,而不是李四1-->
用户名:{
    
    {
    
    obj2.username.value+'1'}}
<!-- 这个就不需要加value了 ,因为username本身就是顶级属性了-->
用户名:{
    
    {
    
    username+'1'}}
</template>

<script setup>

import {
    
    ref} from "vue";

const obj2 = {
    
    username:ref('张三')}
setTimeout(()=>{
    
    
  obj2.username.value = '李四'
},5000)

const {
    
    username} = obj2;


</script>

このrefオブジェクトは、通常のオブジェクト プロパティと同様に、ディープ リアクティブ オブジェクトのプロパティとしてアクセスされると、自動的にラップ解除されます。しかし、浅い反応性オブジェクトはそうではありません。

<template>
<!-- 这个就不需要加value了 ,因为是在深层响应式对象中的一个属性,自动解包-->
年龄:{
    
    {
    
    obj3.age+10}}
</template>

<script setup>

import {
    
    ref} from "vue";

const obj3 = reactive({
    
    age:ref(20)})
setTimeout(()=>{
    
    
  obj3.age = 50;//不用加value 自动解包
},5000)

</script>

refオブジェクトが応答配列の要素である場合、refこのオブジェクトを使用するときに自動的に解凍されません。value

1.8 すべてのケースが自動的に解凍されるわけではなく、refオブジェクトごとに追加するのはvalue面倒です。構文シュガーを使用して置き換えることができます。

ref() を $ref() に変更するだけです。

const btnState = $ref(0)
const obj2 = {
    
    username:$ref('张三')}

糖衣構文を使用するには、表示を有効にする必要があります。

vite.config.js

「@vitejs/plugin-vue」 >= 「^2.0.0」が必要です。

export default defineConfig({
    
    
  plugins: [
    vue({
    
    
      reactivityTransform:true,//显示启用语法糖,配置完之后要重启
    }),
  ]
});

2. レスポンシブな進化 - APIの統合

2.1基本的なsetup()使い方

setup()コンポーネント内で組み合わせAPIを使用するための入口となるフック関数で、オプションAPIコンポーネントで組み合わせAPIを使用する場合に必要となる関数であり、この関数内に組み合わせAPIを記述する必要があります。合成 API を使用して、 や他の関数を使用するなど、この関数内でリアクティブ状態を宣言します。ref()その後reactive()、この関数によって返されるオブジェクトは、これらのリアクティブ状態をテンプレートおよびコンポーネント インスタンスに公開します。コンポーネント インスタンスを通じて追加のオプションにアクセスできるようになりました。

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

export default {
    
    
  setup(){
    
    
    const username = ref('张三');
    return {
    
    
      username//在调用这个属性不用加value,因为在暴露的时候自动解包了
    }
  },
  methods:{
    
    
    getName(){
    
    
      console.log(this.username);//使用this就可以直接调用暴露的属性,
      return this.username;
    }
  },
  mounted(){
    
    
    this.getName();
  }
}
</script>
<template>
<div>{
    
    {
    
    username}}</div>
</template>

setup()関数にはパラメータがあり、最初のパラメータは コンポーネント ですprops標準コンポーネントと同様に、これもprops応答性があり、props新しいコンポーネントが渡されると同期して更新されます。オブジェクトが deconstructed されるとprops、deconstructed 変数の応答性が失われるため、props.xxxformを使用することをお勧めしますprops

export default{
    
    
  props:{
    
    
    username,
  },
  setup(props){
    
    
    console.log(props.username);
  }
}

を構造化する必要がある場合props、またはprop外部関数に何かを渡して応答性を維持する必要がある場合は、toRefs()またはtoRef()関数を使用できます。

export default{
    
    
  props:{
    
    
    username,
  },
  setup(props){
    
    
    const {
    
    username} = toRefs(props);
    //username 是一个ref对象,value是props.username
  }
}

2 番目のパラメーターは Setup コンテキスト オブジェクトで、setup使用される可能性のあるいくつかの値を公開します。コンテキスト オブジェクトは非反応性であり、分解できます。コンポーネント自体が更新されると常に更新されるステートフル オブジェクトですattrsおよびのプロパティはいずれもリアクティブではありません。slotsattrsslots

export default {
    
    
  setup(props, context) {
    
    
    // 透传 Attributes(非响应式的对象,等价于 $attrs)
    console.log(context.attrs)

    // 插槽(非响应式的对象,等价于 $slots)
    console.log(context.slots)

    // 触发事件(函数,等价于 $emit)
    console.log(context.emit)

    // 暴露公共属性(函数)
    console.log(context.expose)
  }
}

2.2 API コア関数の結合

2.2.1ref()
  • パラメータ: すべての値タイプ渡されたパラメータがオブジェクトの場合、そのオブジェクトはreactive()深い応答性を備えたオブジェクトに変換されます。
  • 戻り値: 応答refオブジェクト このオブジェクトには、内部レイアウトを指すプロパティのみが含まれますvalueすべてのvalue操作のペアが追跡されます。
  • シュガー構文: $ref()
  • 例: 前に示した例を参照してください。
2.2.2computed()
  • パラメータ:
    1. 関数を受け取りgetter、読み取り専用のリアクティブrefオブジェクトを返します。
    2. getおよび関数を使用してオブジェクトを受け取りset、書き込み可能なrefオブジェクトを返します。
  • 戻り値: オブジェクトを返します。さまざまなパラメーターに従ってref、読み取り専用または書き込み可能なオブジェクトを返します。ref関数の戻り値は、refプロパティを通じてvalue公開されますgetter
  • シュガー構文: $computed()
<template>
 <div>One的值:{
    
    {
    
    comCountOne}}</div>
 <div>Two的值:{
    
    {
    
    comCountTwo}}</div>
</template>
<script setup>

import {
    
    computed} from "vue";

let count = $ref(0)

//传入一个getter函数 ,返回一个只读的ref对象
const comCountOne = computed(()=>{
    
    
  return count++;
})

//传入一个带有get和set的对象,返回一个可写的ref对象
const comCountTwo = computed({
    
    
  get(){
    
    
    return count
  },
  set(newVale){
    
    
    count=newVale + 5;
  }
})

setTimeout(()=>{
    
    
  comCountTwo.value = 100
},5000)

</script>
2.2.3reactive()
  • パラメータ: オブジェクト
  • 戻り値: オブジェクトのリアクティブ プロキシ オブジェクト
  • 例: 前に示した例を参照してください。
2.2.4readonly()
  • パラメータ: 通常のオブジェクトであってもrefオブジェクトであっても、オブジェクトを受け入れます。
  • 戻り値: 元の値を持つ読み取り専用プロキシを返します。読み取り専用プロキシは深く、ネストされたプロパティへのアクセスは読み取り専用になります。
2.2.5watchEffect()
  • パラメータ:
    1. 最初のパラメータは、実行する副作用関数です。この副作用関数のパラメーターも関数であり、クリーンアップ コールバックを登録するために使用されます。クリーンアップ コールバックは、次回副作用関数が実行されるときに呼び出され、無効な副作用をクリーンアップするために使用できます。
    2. 2 番目のパラメータはオプションです。副作用関数のリフレッシュ タイミングを調整したり、副作用の依存関係をデバッグしたりするために使用されます。デフォルトでは、コンポーネントがレンダリングされる前にリスナーが実行されますが、この設定により、flush:'post'コンポーネントがレンダリングされるまでリスナーが遅延されます (watchPostEffect()関数)。一部の特殊なケースでは、リアクティブな依存関係が変更されたときにすぐにリスナーをトリガーする必要がある場合があります。これはflush:'sync'(watchSyncEffect()関数) によって実現できます。
  • 戻り値: この副作用を停止するために使用される関数を返します。
  • 例:
import {
    
    watchEffect} from "vue";

let count = $ref(0)

watchEffect(()=>{
    
    
  console.log(count);
})

count++;
2.2.6watch()
  • パラメータ:
    1. 最初のパラメータである 1 つ以上のリアクティブ データ ソースは、データ ソースが変更されたときに指定されたコールバック関数を呼び出します。watch()これは遅延リスニングであり、コールバック関数はデータ ソースが変更された場合にのみ実行されます。
      1. 値を返す関数
      2. 1つref
      3. 反応性のあるオブジェクト
      4. 上記の型で構成される配列
    2. 2 番目のパラメータは、変更が発生したときに呼び出されるコールバック関数です。この関数には、新しい値、古い値、および無効な副作用をクリアできる副作用のクリーンアップを登録するために使用されるコールバック関数の 3 つのパラメータがあります。複数のソースをリッスンする場合、コールバック関数は、ソース配列内の新しい値と古い値に対応する 2 つの配列を受け取ります。
    3. 3 番目のパラメーターはオプションで、次のオプションを持つオブジェクトです。
      1. immediate: リスナーが作成されるとすぐにコールバックを起動します。最初に呼び出されたときの古い値は、undefined
      2. deep: ソースがオブジェクトの場合、深いトラバーサルを強制し、深いレベルが変更されたときにコールバックをトリガーします。
      3. flush: コールバック関数のリフレッシュタイミングを調整します。
      4. onTrack, onTrigger: リスナーの依存関係をデバッグします。
  • 戻り値: この副作用を停止するために使用される関数を返します。
import {
    
    watch,ref,reactive} from "vue";

let one = ref(0)//用$ref()创建的ref对象无法使用watch
const state = reactive({
    
    count:0})
//监听ref对象
watch(one,(val,oldVal)=>{
    
    
  console.log("--"+val)
  console.log("--"+oldVal)
})
//一个getter函数
watch(()=>{
    
    return state.count},(count,oldCount)=>{
    
    
  console.log(count)
  console.log(oldCount)
})
//监听多个来源

watch([one,state],([newValOne,newState],[old1,old2])=>{
    
    
  console.log("-newValOne-"+newValOne)
  console.log("-newState-"+newState.count)
  console.log("-old1-"+old1)
  console.log("-old2-"+old2.count)
})

setTimeout(()=>{
    
    
  one.value = 100;
  state.count = 1000;
},5000)

2.3 APIツールの機能を組み合わせる

2.3.1isRef()
  • refパラメータ: この値がオブジェクトであるかどうかを判断するためにチェックされる値
  • 戻り値:trueはいを意味し、それ以外の場合はいいえを意味します
2.3.2unref()
  • パラメータ: 値
  • 戻り値: パラメータがrefオブジェクトの場合は内部値が返され、それ以外の場合はパラメータ自体が返されます。
2.3.3toRef()

リアクティブ オブジェクトのプロパティに基づいて、対応するrefオブジェクトを作成します。この方法で作成されたものは、refソース プロパティと同期したままになります。

  • パラメータ:
    1. 最初のパラメータ、応答オブジェクト
    2. 2 番目のパラメーターは、応答オブジェクトのプロパティ名です。
  • 戻り値:refオブジェクト
  • 糖衣構文: $toRef()、プロンプトが宣言されていませんか?
  • 例:
<template>
      <div>addressRef的值:{
    
    {
    
    addressRef}}</div>
      <div>user.address的值:{
    
    {
    
    user.address}}</div>
</template>
<script setup>

import {
    
    watch,ref,reactive,toRef} from "vue";

const user = reactive({
    
    
  username:'张三',
  address:'长春'
})

const addressRef = toRef(user,'address')

setTimeout(()=>{
    
    
  user.address = "松原"
},5000)
setTimeout(()=>{
    
    
  addressRef.value = "白山"
},10000)

</script>
2.3.4toRefs()

リアクティブ オブジェクトを通常のオブジェクトに変換します。この通常のオブジェクトの各プロパティは、refソース オブジェクトの対応するプロパティを指すオブジェクトです。それぞれをref使用toRef()して作成されます。toRefs()呼び出し時にソース オブジェクトの列挙可能なプロパティのみが作成されref、存在しない可能性のあるプロパティは作成されません。

  • パラメータ: リアクティブオブジェクト
  • 戻り値: 通常のオブジェクト
  • 例:
const user = reactive({
    
    
  username:'张三',
  address:'长春'
})
const userOfRefs = toRefs(user);
const {
    
    usernameRef,addressRef} = userOfRefs;//解构也不会丢失响应性
2.3.5isProxy()

オブジェクトにreactive()、、、、、によって作成readonly()れたプロキシがあるかどうかを確認しますshallowReactive()shallowReadonly()

2.3.6isReactive()

オブジェクトにプロキシが作成されているreactive()かどうかを確認するshallowReactive()

2.3.7isReadonly()

オブジェクトにプロキシが作成されているreadonly()かどうかを確認するshallowReadonly()

2.4 複合 API – 依存関係の注入

2.4.1provide()

子孫コンポーネントによって注入できる値を提供します。provide()同期的に呼び出されますsetup()

  • パラメータ:
    1. 最初のパラメータである注入されるキーは、文字列またはsymbol
    2. 2 番目のパラメーターは、注入される値です。この値は、ref子孫コンポーネントがプロバイダーとの応答関係を確立できるオブジェクトにすることができます。
  • 戻り値: なし
  • 例:
import {
    
    provide, reactive,ref} from 'vue'

const obj = reactive({
    
    
  user:{
    
    
    username:'张三',
    address:'长春'
  },
  task:{
    
    
    completeNumber:0,
    craft:{
    
    
      version:1
    }
  }
})

provide('obj',obj)

const countRef = ref(0)

provide('count',countRef)

setTimeout(()=>{
    
    
  countRef.value = 1000;
  obj.user.address='成都'
  obj.task.completeNumber = 100
  obj.task.craft.version = 2.4
},5000)

2.4.2 アプリケーション層Provide

vue インスタンスにもprovide()関数があり、この関数によって提供されるデータをアプリケーション内のすべてのコンポーネントに注入できます。

2.4.3inject()

上位コンポーネントによって提供されたデータを現在のコンポーネントに注入します。inject()同期的に呼び出されますsetup()

  • パラメータ:
    1. 最初のパラメータはキー値です。これは、祖先コンポーネントによって提供されるデータのキーです。祖先コンポーネント上に同じキーの値を提供するコンポーネントが複数ある場合、最も近いコンポーネントが遠いコンポーネントによって提供された値を上書きします。そうでない場合は、デフォルト値を返しますundefined
    2. 2 番目のパラメータはデフォルト値です。
    3. デフォルト値が関数の場合、3 番目のパラメータを渡す必要があります。このパラメータによって渡される値は次のとおりです。false
  • 戻り値: 祖先コンポーネントによって提供されたデータを返します。
  • 例:
<template>
 <div>{
    
    {
    
    countRef}}</div>
          <div>地址:{
    
    {
    
    obj.user.address}}</div>
          <div>数量:{
    
    {
    
    obj.task.completeNumber + 10 }}</div>
          <div>版本:{
    
    {
    
     obj.task.craft.version}}</div>
</template>
<script setup>

import {
    
    inject} from "vue";
const obj = inject('obj')
const countRef = inject('count')
setTimeout(()=>{
    
    
  countRef.value = 50000;
  obj.user.address='武汉'
  obj.task.completeNumber = 700
  obj.task.craft.version = 12.5
},20000)

</script>
2.4.4 レスポンシブデータでの使用

setTimeout()上の例では、2 つの関数が応答データを直接変更していることがわかります。複数のファイルがデータを直接変更する場合、データの変更がわからないため、可能な限り、応答状態の変更をサプライヤー コンポーネントに保持し、状態の宣言と変更操作が一貫していることを確認する必要があります。成分。上の例を変更してみましょう。

ルートコンポーネント:

<script setup>

import {
    
    provide, reactive,ref,readonly} from 'vue'

const obj = reactive({
    
    
  user:{
    
    
    username:'张三',
    address:'长春'
  },
  task:{
    
    
    completeNumber:0,
    craft:{
    
    
      version:1
    }
  }
})

provide('obj',readonly(obj))//用readonly包装,这样后代组件就不能直接修改了

let countRef = ref(0)

provide('count',readonly(countRef))

setTimeout(()=>{
    
    
  countRef.value = 1000;
  obj.user.address='成都'
  obj.task.completeNumber = 100
  obj.task.craft.version = 2.4
},5000)

function changeData() {
    
    
  countRef.value = 50000;
  obj.user.address='武汉'
  obj.task.completeNumber = 700
  obj.task.craft.version = 12.5
}
provide('changeData',changeData)//把这个函数提供给后代组件,后代都通过这个方法进行数据更新
</script>

子孫コンポーネント

const obj = inject('obj')
const countRef = inject('count')
const changeData = inject('changeData')
setTimeout(()=>{
    
    
  changeData();//调用祖先组件提供更改数据的方法
},20000)
2.4.5 シンボルをインジェクション名として使用する

インジェクション名として文字列を使用すると競合が発生する可能性がありますが、文字列を使用するとSymbol競合を回避できます。

おすすめ

転載: blog.csdn.net/Zhang_YingJie/article/details/127514896