toRow和markRow的用法以及使用场景

421 阅读2分钟

1. toRaw vs markRaw

1.1 基本概念

  • toRaw: 返回响应式对象的原始对象,用于临时获取原始数据结构,标记过后将会失去响应式
  • markRaw: 标记一个对象永远不会转换为响应式对象,返回对象本身

1.2 使用对比

// toRaw 示例
const state = reactive({
  count: 0,
  obj: {
    nested: 'value'
  }
})

const rawState = toRaw(state)
// rawState 是普通对象,修改不会触发更新
rawState.count++ // 不会触发视图更新

// markRaw 示例
const obj = markRaw({
  count: 0,
  nested: {
    value: 'hello'
  }
})

const state = reactive({
  data: obj
})

// obj 永远不会被转换为响应式
state.data.count++ // 不会触发视图更新

2. 实际应用场景

2.1 使用 toRaw 的场景

  1. 性能优化
const state = reactive({
  list: [
    /* 大量数据 */
  ]
})

// 在不需要响应式的地方使用原始数据
const rawList = toRaw(state.list)
const result = heavyComputation(rawList) // 避免响应式转换的性能开销
  1. 与外部库集成
const state = reactive({
  chartData: {
    labels: ['A', 'B', 'C'],
    values: [1, 2, 3]
  }
})

// 传递原始数据给第三方库
const rawChartData = toRaw(state.chartData)
thirdPartyChart.setData(rawChartData)

2.2 使用 markRaw 的场景

  1. 不需要响应式的数据结构
// 工具类实例
class Helper {
  format(value) {
    return `formatted: ${value}`
  }
}

const state = reactive({
  // 工具类不需要是响应式的
  helper: markRaw(new Helper()),
  data: 'test'
})

// helper 方法调用不会触发响应式
console.log(state.helper.format(state.data))
  1. 大型不可变对象
const constants = markRaw({
  API_ENDPOINTS: {
    users: '/api/users',
    posts: '/api/posts',
    // ... 更多静态配置
  },
  APP_CONFIG: {
    // ... 应用配置
  }
})

const store = reactive({
  config: constants, // 不会被转换为响应式
  // ... 其他响应式数据
})

3. 性能优化实践

3.1 避免不必要的响应式转换

const store = {
  state: reactive({
    // 响应式数据
    userProfile: {
      name: '',
      email: ''
    }
  }),
  
  // 工具方法和常量使用 markRaw
  utils: markRaw({
    formatDate: (date) => { /* ... */ },
    validateEmail: (email) => { /* ... */ }
  }),
  
  // 静态配置使用 markRaw
  config: markRaw({
    apiBase: 'https://api.example.com',
    timeout: 5000
  })
}

3.2 大数据处理优化

const state = reactive({
  items: []
})

function processLargeData(data) {
  // 使用原始数据进行计算
  const rawItems = toRaw(state.items)
  const result = heavyComputation(rawItems)
  
  // 只在需要更新视图时使用响应式数据
  state.items = result
}

4. 与其他 API 配合使用

4.1 与 ref 配合

const count = ref(0)
const rawCount = toRaw(count)

// ref 的原始值需要通过 .value 访问
console.log(rawCount.value)

// markRaw 用于 ref 的值
const obj = markRaw({ count: 0 })
const objRef = ref(obj)
// obj 保持非响应式

4.2 与 computed 配合

const state = reactive({
  firstName: 'John',
  lastName: 'Doe'
})

const fullName = computed(() => {
  // 在计算属性中使用原始值进行复杂计算
  const raw = toRaw(state)
  return `${raw.firstName} ${raw.lastName}`
})

5. 注意事项

  1. 保持响应性
const state = reactive({
  count: 0
})

const raw = toRaw(state)
raw.count++ // 不会触发更新

// 如果需要触发更新,应该使用响应式对象
state.count++ // 会触发更新
  1. markRaw 的不可逆性
const obj = markRaw({
  count: 0
})

// 即使包装在 reactive 中也不会变成响应式
const state = reactive({
  data: obj
})

state.data.count++ // 不会触发更新
  1. 深层数据结构
const nested = reactive({
  obj: markRaw({
    count: 0,
    deep: {
      value: 1
    }
  })
})

// 整个对象及其嵌套属性都不会是响应式的
nested.obj.count++ // 不会触发更新
nested.obj.deep.value++ // 不会触发更新
  1. 与 TypeScript 使用
interface RawObject {
  count: number
  nested: {
    value: string
  }
}

// 标记原始类型
const obj = markRaw<RawObject>({
  count: 0,
  nested: {
    value: 'hello'
  }
})

// 获取原始类型
const raw = toRaw(reactive(obj)) as RawObject