-import { isReactive, reactive, shallowReactive } from '../../src/index'
+import {
+ effect,
+ isReactive,
+ reactive,
+ readonly,
+ shallowReactive,
+} from '../../src/index'
import { renderList } from '../../src/helpers/renderList'
describe('renderList', () => {
const shallowReactiveArray = shallowReactive([{ foo: 1 }])
expect(renderList(shallowReactiveArray, isReactive)).toEqual([false])
})
+
+ it('should not allow mutation', () => {
+ const arr = readonly(reactive([{ foo: 1 }]))
+ expect(
+ renderList(arr, item => {
+ ;(item as any).foo = 0
+ return item.foo
+ }),
+ ).toEqual([1])
+ expect(
+ `Set operation on key "foo" failed: target is readonly.`,
+ ).toHaveBeenWarned()
+ })
+
+ it('should trigger effect for deep mutations in readonly reactive arrays', () => {
+ const arr = reactive([{ foo: 1 }])
+ const readonlyArr = readonly(arr)
+
+ let dummy
+ effect(() => {
+ dummy = renderList(readonlyArr, item => item.foo)
+ })
+ expect(dummy).toEqual([1])
+
+ arr[0].foo = 2
+ expect(dummy).toEqual([2])
+ })
})
import type { VNode, VNodeChild } from '../vnode'
import {
isReactive,
+ isReadonly,
isShallow,
shallowReadArray,
toReactive,
+ toReadonly,
} from '@vue/reactivity'
import { isArray, isObject, isString } from '@vue/shared'
import { warn } from '../warning'
if (sourceIsArray || isString(source)) {
const sourceIsReactiveArray = sourceIsArray && isReactive(source)
let needsWrap = false
+ let isReadonlySource = false
if (sourceIsReactiveArray) {
needsWrap = !isShallow(source)
+ isReadonlySource = isReadonly(source)
source = shallowReadArray(source)
}
ret = new Array(source.length)
for (let i = 0, l = source.length; i < l; i++) {
ret[i] = renderItem(
- needsWrap ? toReactive(source[i]) : source[i],
+ needsWrap
+ ? isReadonlySource
+ ? toReadonly(toReactive(source[i]))
+ : toReactive(source[i])
+ : source[i],
i,
undefined,
cached && cached[i],