最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Vue3響應(yīng)式中4個進(jìn)階API的核心使用場景

 更新時間:2025年12月01日 09:05:36   作者:良山有風(fēng)來  
這篇文章主要帶大家深入了解一下Vue 3響應(yīng)式系統(tǒng)中那些被低估的進(jìn)階API,例如shallowRef,markRaw等,讓你的應(yīng)用性能瞬間起飛,快跟隨小編一起學(xué)習(xí)一下吧

從性能瓶頸說起

不知道你有沒有遇到過這樣的場景:一個包含數(shù)千條數(shù)據(jù)的表格,每次操作都卡頓得讓人抓狂;或者一個復(fù)雜的表單,每次輸入都會觸發(fā)不必要的重新渲染。明明用了Vue 3的響應(yīng)式系統(tǒng),性能卻越來越差。

這其實就是響應(yīng)式系統(tǒng)的過度使用導(dǎo)致的。Vue 3的響應(yīng)式確實強大,但如果不加節(jié)制地使用,反而會成為性能殺手。今天我就帶你深入了解Vue 3響應(yīng)式系統(tǒng)中那些被低估的進(jìn)階API,讓你的應(yīng)用性能瞬間起飛!

讀完本文,你將掌握shallowRef、markRaw等API的核心使用場景,學(xué)會在什么情況下該用它們來優(yōu)化性能。更重要的是,你會獲得一套完整的性能優(yōu)化思路,讓你在面對復(fù)雜場景時游刃有余。

重新認(rèn)識Vue 3響應(yīng)式

在深入進(jìn)階API之前,我們先快速回顧一下Vue 3響應(yīng)式的基礎(chǔ)知識。Vue 3使用Proxy來實現(xiàn)響應(yīng)式,這意味著當(dāng)你修改一個響應(yīng)式對象的任何屬性時,都會觸發(fā)依賴更新。

// 基礎(chǔ)響應(yīng)式示例
import { reactive, watchEffect } from 'vue'

const state = reactive({
  user: {
    name: '張三',
    profile: {
      age: 25,
      hobbies: ['籃球', '閱讀']
    }
  }
})

// 任何嵌套屬性的修改都會觸發(fā)這個effect
watchEffect(() => {
  console.log('用戶信息更新了:', state.user.profile.age)
})

// 修改age會觸發(fā)effect
state.user.profile.age = 26
// 甚至添加新的hobby也會觸發(fā)
state.user.profile.hobbies.push('編程')

看到問題了嗎?即使我們只關(guān)心age的變化,但任何嵌套屬性的修改都會觸發(fā)重新執(zhí)行。在大型應(yīng)用中,這種細(xì)粒度的響應(yīng)式可能會帶來不必要的性能開銷。

shallowRef:淺層響應(yīng)的智慧

shallowRef是ref的"輕量版",它只對.value本身的變化進(jìn)行響應(yīng),不會遞歸地將嵌套對象轉(zhuǎn)為響應(yīng)式。

import { shallowRef, watchEffect } from 'vue'

// 使用shallowRef
const userData = shallowRef({
  basicInfo: {
    name: '李四',
    age: 30
  },
  preferences: {
    theme: 'dark',
    language: 'zh-CN'
  }
})

// 只有直接修改userData.value才會觸發(fā)effect
watchEffect(() => {
  console.log('用戶數(shù)據(jù)發(fā)生變化')
})

// 這個不會觸發(fā)effect!
userData.value.basicInfo.name = '王五'

// 但這個會觸發(fā)effect
userData.value = {
  basicInfo: { name: '王五', age: 30 },
  preferences: { theme: 'light', language: 'en-US' }
}

那么什么時候該用shallowRef呢?

場景1:大型對象或數(shù)組

當(dāng)你有一個很大的數(shù)據(jù)對象,但只需要在整體替換時更新視圖,這時候shallowRef就是最佳選擇。

// 從服務(wù)器獲取的大型數(shù)據(jù)集
const largeDataset = shallowRef([])

// 模擬數(shù)據(jù)獲取
async function fetchData() {
  const response = await fetch('/api/large-data')
  const data = await response.json()
  
  // 整體替換,觸發(fā)更新
  largeDataset.value = data
}

// 內(nèi)部修改不會觸發(fā)不必要的更新
function updateItem(index, newItem) {
  largeDataset.value[index] = newItem
  // 這里不會觸發(fā)組件重新渲染!
}

場景2:第三方庫實例

當(dāng)你需要集成第三方庫,比如圖表庫、地圖庫的實例時:

import { shallowRef, onMounted } from 'vue'
import * as echarts from 'echarts'

const chartInstance = shallowRef(null)
const chartData = ref([])

onMounted(() => {
  // 初始化圖表實例
  const chart = echarts.init(document.getElementById('chart'))
  chartInstance.value = chart
  
  // 只有chartData變化時才更新圖表
  watchEffect(() => {
    if (chartInstance.value) {
      chartInstance.value.setOption({
        series: [{ data: chartData.value }]
      })
    }
  })
})

markRaw:徹底擺脫響應(yīng)式

有時候,我們根本不需要某些數(shù)據(jù)變成響應(yīng)式,這時候markRaw就派上用場了。markRaw標(biāo)記一個對象,讓它永遠(yuǎn)不會被轉(zhuǎn)為響應(yīng)式。

import { reactive, markRaw, watchEffect } from 'vue'

// 配置對象,不需要響應(yīng)式
const staticConfig = markRaw({
  apiBaseUrl: 'https://api.example.com',
  timeout: 5000,
  retryCount: 3
})

const state = reactive({
  user: null,
  // 即使放在reactive對象里,config也不會變成響應(yīng)式
  config: staticConfig
})

watchEffect(() => {
  console.log('狀態(tài)變化')
})

// 這個修改不會觸發(fā)effect!
state.config.timeout = 10000

使用場景:常量配置和工具對象

// 常量配置
const APP_CONFIG = markRaw({
  VERSION: '1.0.0',
  FEATURES: {
    DARK_MODE: true,
    OFFLINE_SUPPORT: false
  }
})

// 工具函數(shù)集合
const utils = markRaw({
  formatDate(date) {
    return new Intl.DateTimeFormat('zh-CN').format(date)
  },
  debounce(fn, delay) {
    let timer
    return (...args) => {
      clearTimeout(timer)
      timer = setTimeout(() => fn.apply(this, args), delay)
    }
  }
})

const store = reactive({
  config: APP_CONFIG,
  utils: utils,
  userData: null
})

在組件選項API中的使用

import { markRaw } from 'vue'

export default {
  data() {
    return {
      // 標(biāo)記第三方庫實例為非響應(yīng)式
      mapInstance: markRaw(null),
      markers: []
    }
  },
  
  mounted() {
    // 初始化地圖,這個實例不需要響應(yīng)式
    this.mapInstance = markRaw(new MapLibrary('#map'))
    
    this.loadMarkers()
  },
  
  methods: {
    async loadMarkers() {
      const markers = await fetchMarkers()
      this.markers = markers
      
      // 直接操作非響應(yīng)式實例,性能更好
      markers.forEach(marker => {
        this.mapInstance.addMarker(marker)
      })
    }
  }
}

shallowReactive:表層響應(yīng)的平衡點

shallowReactive是reactive的淺層版本,只對根級別屬性進(jìn)行響應(yīng)式跟蹤。

import { shallowReactive, watchEffect } from 'vue'

const state = shallowReactive({
  level1: {
    level2: {
      value: '初始值'
    }
  },
  count: 0
})

watchEffect(() => {
  console.log('狀態(tài)變化:', state.count)
})

// 這個會觸發(fā)effect - 根級別屬性
state.count++

// 這個不會觸發(fā)effect - 嵌套屬性
state.level1.level2.value = '新值'

實際應(yīng)用場景:配置管理

// 應(yīng)用配置管理
function useAppConfig() {
  const config = shallowReactive({
    theme: {
      colors: {
        primary: '#1890ff',
        secondary: '#52c41a'
      },
      spacing: {
        small: '8px',
        medium: '16px'
      }
    },
    features: {
      analytics: true,
      notifications: false
    }
  })
  
  // 只有切換主題整體時才會更新
  function switchTheme(newTheme) {
    config.theme = newTheme
  }
  
  // 修改具體顏色不會觸發(fā)不必要的更新
  function updatePrimaryColor(color) {
    config.theme.colors.primary = color
  }
  
  return {
    config,
    switchTheme,
    updatePrimaryColor
  }
}

toRaw:獲取原始對象

toRaw返回reactive或readonly代理的原始對象。這在需要直接操作原始數(shù)據(jù),或者將數(shù)據(jù)傳遞給不支持代理的第三方庫時特別有用。

import { reactive, toRaw, watchEffect } from 'vue'

const state = reactive({
  items: ['item1', 'item2']
})

watchEffect(() => {
  console.log('數(shù)組變化了')
})

// 通過代理操作,會觸發(fā)effect
state.items.push('item3')

// 獲取原始對象操作,不會觸發(fā)effect
const rawState = toRaw(state)
rawState.items.push('item4') // 不會觸發(fā)上面的effect

// 需要傳遞給第三方庫時
function saveToLocalStorage() {
  const rawData = toRaw(state)
  localStorage.setItem('app-state', JSON.stringify(rawData))
}

性能優(yōu)化實戰(zhàn):大型數(shù)據(jù)表格

讓我們來看一個實際的性能優(yōu)化案例。假設(shè)我們有一個需要顯示數(shù)千行數(shù)據(jù)的表格:

import { shallowRef, computed, onMounted } from 'vue'

export function useDataTable() {
  // 使用shallowRef存儲大量數(shù)據(jù)
  const rawData = shallowRef([])
  
  // 分頁和排序狀態(tài)使用普通ref
  const currentPage = ref(1)
  const pageSize = ref(50)
  const sortBy = ref('id')
  
  // 計算當(dāng)前頁數(shù)據(jù)
  const currentPageData = computed(() => {
    const data = rawData.value
    const start = (currentPage.value - 1) * pageSize.value
    const end = start + pageSize.value
    
    return data
      .slice()
      .sort((a, b) => {
        if (a[sortBy.value] < b[sortBy.value]) return -1
        if (a[sortBy.value] > b[sortBy.value]) return 1
        return 0
      })
      .slice(start, end)
  })
  
  onMounted(async () => {
    // 模擬獲取大量數(shù)據(jù)
    const response = await fetch('/api/large-dataset')
    const data = await response.json()
    rawData.value = data
  })
  
  // 更新單行數(shù)據(jù) - 不會觸發(fā)不必要重新渲染
  function updateRow(rowId, newData) {
    const rowIndex = rawData.value.findIndex(row => row.id === rowId)
    if (rowIndex !== -1) {
      rawData.value[rowIndex] = { ...rawData.value[rowIndex], ...newData }
    }
  }
  
  return {
    currentPageData,
    currentPage,
    pageSize,
    sortBy,
    updateRow
  }
}

組合使用:構(gòu)建高性能狀態(tài)管理

在實際項目中,我們往往需要組合使用這些API來構(gòu)建完整的狀態(tài)管理方案。

import { reactive, shallowRef, markRaw, toRaw } from 'vue'

// 應(yīng)用狀態(tài)管理
export function useAppStore() {
  // 用戶信息 - 需要深度響應(yīng)式
  const user = reactive({
    profile: {
      name: '',
      email: ''
    },
    preferences: {}
  })
  
  // 業(yè)務(wù)數(shù)據(jù) - 使用淺層響應(yīng)式
  const businessData = shallowRef({
    products: [],
    orders: [],
    customers: []
  })
  
  // 配置和工具 - 不需要響應(yīng)式
  const constants = markRaw({
    API_ENDPOINTS: {
      PRODUCTS: '/api/products',
      ORDERS: '/api/orders'
    },
    VALIDATION_RULES: {
      EMAIL: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
      PHONE: /^1[3-9]\d{9}$/
    }
  })
  
  // 第三方服務(wù)實例
  const services = markRaw({
    analytics: null,
    payment: null
  })
  
  // 初始化服務(wù)
  function initializeServices() {
    services.analytics = new AnalyticsService()
    services.payment = new PaymentService(constants.API_ENDPOINTS)
  }
  
  // 批量更新業(yè)務(wù)數(shù)據(jù)
  async function updateBusinessData() {
    const [products, orders, customers] = await Promise.all([
      fetch(constants.API_ENDPOINTS.PRODUCTS),
      fetch(constants.API_ENDPOINTS.ORDERS),
      fetch(constants.API_ENDPOINTS.CUSTOMERS)
    ])
    
    // 整體替換,觸發(fā)一次更新
    businessData.value = {
      products: await products.json(),
      orders: await orders.json(),
      customers: await customers.json()
    }
  }
  
  // 導(dǎo)出數(shù)據(jù)(移除響應(yīng)式)
  function exportData() {
    return {
      user: toRaw(user),
      businessData: toRaw(businessData.value),
      constants: toRaw(constants)
    }
  }
  
  return {
    user,
    businessData,
    constants,
    services,
    initializeServices,
    updateBusinessData,
    exportData
  }
}

避坑指南:常見誤用場景

雖然這些進(jìn)階API很強大,但使用不當(dāng)也會帶來問題。下面是一些常見的誤用場景:

誤用1:在需要深度響應(yīng)式時使用shallowRef

// ? 錯誤用法
const formState = shallowRef({
  fields: {
    username: '',
    password: ''
  }
})

// 表單字段變化不會觸發(fā)更新!
formState.value.fields.username = 'new username'

// ? 正確用法:需要深度響應(yīng)式時使用reactive
const formState = reactive({
  fields: {
    username: '',
    password: ''
  }
})

誤用2:過度使用markRaw

// ? 錯誤用法:把需要響應(yīng)式的數(shù)據(jù)標(biāo)記為非響應(yīng)式
const state = reactive({
  user: markRaw({
    name: '張三',
    // 這個name變化不會觸發(fā)更新!
  })
})

// ? 正確用法:只在確實不需要響應(yīng)式時使用markRaw
const state = reactive({
  user: {
    name: '張三'
  },
  config: markRaw({
    // 配置信息確實不需要響應(yīng)式
    apiUrl: 'https://api.example.com'
  })
})

測試與調(diào)試技巧

使用這些API時,合適的測試和調(diào)試方法很重要:

import { isReactive, isRef, isReadonly, toRaw } from 'vue'

// 調(diào)試函數(shù),檢查響應(yīng)式狀態(tài)
function debugReactive(obj, name = '未知對象') {
  console.group(`響應(yīng)式調(diào)試: ${name}`)
  console.log('原始對象:', toRaw(obj))
  console.log('是響應(yīng)式對象:', isReactive(obj))
  console.log('是ref對象:', isRef(obj))
  console.log('是只讀對象:', isReadonly(obj))
  console.groupEnd()
}

// 在組件中使用
const state = reactive({ count: 0 })
const shallowState = shallowReactive({ nested: { value: 1 } })

debugReactive(state, '深度響應(yīng)式狀態(tài)')
debugReactive(shallowState, '淺層響應(yīng)式狀態(tài)')
debugReactive(shallowState.nested, '嵌套對象')

總結(jié)與最佳實踐

通過今天的學(xué)習(xí),相信你已經(jīng)對Vue 3響應(yīng)式系統(tǒng)的進(jìn)階API有了更深入的理解。讓我們最后總結(jié)一下各個API的使用場景:

  • shallowRef 適用于大型對象或數(shù)組,當(dāng)你只需要在整體替換時更新視圖的場景。
  • markRaw 適用于常量配置、工具函數(shù)、第三方庫實例等確實不需要響應(yīng)式的場景。
  • shallowReactive 適用于那些只需要表層響應(yīng)式,嵌套數(shù)據(jù)變化不需要觸發(fā)更新的場景。
  • toRaw 適用于需要直接操作原始數(shù)據(jù),或者與第三方庫交互的場景。

記住,性能優(yōu)化的核心思想是:在保證功能正確的前提下,盡量減少不必要的響應(yīng)式跟蹤。不是所有數(shù)據(jù)都需要響應(yīng)式,選擇合適的工具才能構(gòu)建出既功能完善又性能優(yōu)異的Vue應(yīng)用。

以上就是詳解Vue3響應(yīng)式中4個進(jìn)階API的核心使用場景的詳細(xì)內(nèi)容,更多關(guān)于Vue響應(yīng)式API的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue3發(fā)送post請求出現(xiàn)400?Bad?Request報錯的解決辦法

    Vue3發(fā)送post請求出現(xiàn)400?Bad?Request報錯的解決辦法

    這篇文章主要給大家介紹了關(guān)于Vue3發(fā)送post請求出現(xiàn)400?Bad?Request報錯的解決辦法,文中通過實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-02-02
  • Vue自定義指令的使用詳細(xì)介紹

    Vue自定義指令的使用詳細(xì)介紹

    我們看到的v-開頭的行內(nèi)屬性,都是指令,不同的指令可以完成或?qū)崿F(xiàn)不同的功能,對普通 DOM元素進(jìn)行底層操作,這時候就會用到自定義指令。除了核心功能默認(rèn)內(nèi)置的指令 (v-model 和 v-show),Vue 也允許注冊自定義指令
    2022-09-09
  • vue基于Element構(gòu)建自定義樹的示例代碼

    vue基于Element構(gòu)建自定義樹的示例代碼

    本篇文章主要介紹了vue基于Element構(gòu)建自定義樹的示例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • vue腳手架搭建過程圖解

    vue腳手架搭建過程圖解

    vue腳手架是個好東西,能夠快速搭建vue單頁面應(yīng)用,vue是基于node環(huán)境的,所以要先安裝node。下面通過圖文并茂的形式給大家介紹vue腳手架搭建過程圖解,感興趣的朋友一起看看吧
    2018-06-06
  • 詳解在vue開發(fā)中如何利用.env文件

    詳解在vue開發(fā)中如何利用.env文件

    我們在 vue 項目的目錄中經(jīng)常看到 env 開頭的文件,在文件內(nèi)聲明一些變量,這些變量就是一些配置變量,在不同環(huán)境下可使用的變量,本文我們將給大家介紹在vue開發(fā)中如何利用.env文件,需要的朋友可以參考下
    2023-10-10
  • 淺談mint-ui loadmore組件注意的問題

    淺談mint-ui loadmore組件注意的問題

    下面小編就為大家?guī)硪黄獪\談mint-ui loadmore組件注意的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • Vue手把手教你擼一個 beforeEnter 鉤子函數(shù)

    Vue手把手教你擼一個 beforeEnter 鉤子函數(shù)

    這篇文章主要介紹了Vue手把手教你擼一個 beforeEnter 鉤子函數(shù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • vue修改數(shù)據(jù)頁面無效的解決方案

    vue修改數(shù)據(jù)頁面無效的解決方案

    這篇文章主要介紹了vue修改數(shù)據(jù)頁面無效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Vue?electron零基礎(chǔ)使用教程

    Vue?electron零基礎(chǔ)使用教程

    Electron也可以快速地將你的網(wǎng)站打包成一個原生應(yīng)用發(fā)布,下面這篇文章主要給大家介紹了關(guān)于Vue和React中快速使用Electron的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • Vue3中使用this的詳細(xì)教程

    Vue3中使用this的詳細(xì)教程

    在vue3中新的組合式API中沒有this,那我們?nèi)绻枰玫絫his怎么辦?下面這篇文章主要給大家介紹了關(guān)于Vue3中使用this的詳細(xì)教程,需要的朋友可以參考下
    2023-07-07

最新評論

建水县| 石棉县| 徐水县| 双鸭山市| 绥宁县| 车险| 万盛区| 林口县| 台江县| 莱州市| 碌曲县| 广饶县| 富宁县| 多伦县| 英山县| 翼城县| 阜南县| 濮阳县| 吉林市| 钟祥市| 星座| 康保县| 全椒县| 宁阳县| 沽源县| 兴隆县| 白银市| 珲春市| 鹤岗市| 肥乡县| 景泰县| 南岸区| 吉水县| 枣强县| 昭通市| 澄江县| 南郑县| 宜宾县| 枣强县| 江津市| 林西县|