getRestElement,
renderEffect,
} from '../src'
-import { nextTick, ref, shallowRef, triggerRef } from '@vue/runtime-dom'
+import {
+ nextTick,
+ reactive,
+ readonly,
+ ref,
+ shallowRef,
+ triggerRef,
+} from '@vue/runtime-dom'
import { makeRender } from './_utils'
const define = makeRender()
await nextTick()
expectCalledTimesToBe('Clear rows', 1, 0, 0, 0)
})
+
+ describe('readonly source', () => {
+ test('should not allow mutation', () => {
+ const arr = readonly(reactive([{ foo: 1 }]))
+
+ const { host } = define(() => {
+ const n1 = createFor(
+ () => arr,
+ (item, key, index) => {
+ const span = document.createElement('li')
+ renderEffect(() => {
+ item.value.foo = 0
+ span.innerHTML = `${item.value.foo}`
+ })
+ return span
+ },
+ idx => idx,
+ )
+ return n1
+ }).render()
+
+ expect(host.innerHTML).toBe('<li>1</li><!--for-->')
+ expect(
+ `Set operation on key "foo" failed: target is readonly.`,
+ ).toHaveBeenWarned()
+ })
+
+ test('should trigger effect for deep mutations', async () => {
+ const arr = reactive([{ foo: 1 }])
+ const readonlyArr = readonly(arr)
+
+ const { host } = define(() => {
+ const n1 = createFor(
+ () => readonlyArr,
+ (item, key, index) => {
+ const span = document.createElement('li')
+ renderEffect(() => {
+ span.innerHTML = `${item.value.foo}`
+ })
+ return span
+ },
+ idx => idx,
+ )
+ return n1
+ }).render()
+
+ expect(host.innerHTML).toBe('<li>1</li><!--for-->')
+
+ arr[0].foo = 2
+ await nextTick()
+ expect(host.innerHTML).toBe('<li>2</li><!--for-->')
+ })
+ })
})
EffectScope,
type ShallowRef,
isReactive,
+ isReadonly,
isShallow,
pauseTracking,
resetTracking,
shallowReadArray,
shallowRef,
toReactive,
+ toReadonly,
} from '@vue/reactivity'
import { getSequence, isArray, isObject, isString } from '@vue/shared'
import { createComment, createTextNode } from './dom/node'
type ResolvedSource = {
values: any[]
needsWrap: boolean
+ isReadonlySource: boolean
keys?: string[]
}
function normalizeSource(source: any): ResolvedSource {
let values = source
let needsWrap = false
+ let isReadonlySource = false
let keys
if (isArray(source)) {
if (isReactive(source)) {
needsWrap = !isShallow(source)
values = shallowReadArray(source)
+ isReadonlySource = isReadonly(source)
}
} else if (isString(source)) {
values = source.split('')
}
}
}
- return { values, needsWrap, keys }
+ return {
+ values,
+ needsWrap,
+ isReadonlySource,
+ keys,
+ }
}
function getItem(
- { keys, values, needsWrap }: ResolvedSource,
+ { keys, values, needsWrap, isReadonlySource }: ResolvedSource,
idx: number,
): [item: any, key: any, index?: number] {
- const value = needsWrap ? toReactive(values[idx]) : values[idx]
+ const value = needsWrap
+ ? isReadonlySource
+ ? toReadonly(toReactive(values[idx]))
+ : toReactive(values[idx])
+ : values[idx]
if (keys) {
return [value, keys[idx], idx]
} else {