const n2 = t0()
_setTemplateRef(n2, "foo", void 0, true)
return n2
- }, null, 4)
+ }, undefined, 4)
return n0
}"
`;
const x4 = _child(n4)
_renderEffect(() => _setText(x4, _toDisplayString(_for_item1.value+_for_item0.value)))
return n4
- }, null, 1)
+ }, undefined, 1)
return n5
})
return n0
const t0 = _template("<tr> </tr>", true)
export function render(_ctx) {
+ let _selector0_0
const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
const n2 = t0()
const x2 = _child(n2)
_setText(x2, _toDisplayString(_ctx.selected === _for_item0.value.id ? 'danger' : ''))
})
return n2
- }, (row) => (row.id))
- const _selector0_0 = n0.useSelector(() => _ctx.selected)
+ }, (row) => (row.id), undefined, ({ createSelector }) => {
+ _selector0_0 = createSelector(() => _ctx.selected)
+ })
return n0
}"
`;
const t0 = _template("<tr></tr>", true)
export function render(_ctx) {
+ let _selector0_0
const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
const n2 = t0()
_selector0_0(() => {
_setClass(n2, _ctx.selected === _for_item0.value.id ? 'danger' : '')
})
return n2
- }, (row) => (row.id))
- const _selector0_0 = n0.useSelector(() => _ctx.selected)
+ }, (row) => (row.id), undefined, ({ createSelector }) => {
+ _selector0_0 = createSelector(() => _ctx.selected)
+ })
return n0
}"
`;
const t0 = _template("<tr></tr>", true)
export function render(_ctx) {
+ let _selector0_0
const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
const n2 = t0()
_selector0_0(() => {
_setClass(n2, { danger: _for_item0.value.id === _ctx.selected })
})
return n2
- }, (row) => (row.id))
- const _selector0_0 = n0.useSelector(() => _ctx.selected)
+ }, (row) => (row.id), undefined, ({ createSelector }) => {
+ _selector0_0 = createSelector(() => _ctx.selected)
+ })
return n0
}"
`;
const n0 = _createFor(() => (_ctx.list), (_for_item0) => {
const n2 = t0()
return n2
- }, null, 4)
+ }, undefined, 4)
return n0
}"
`;
keyProp,
idMap,
)
- const patternFrag: CodeFragment[] = []
+ const selectorDeclarations: CodeFragment[] = []
+ const selectorSetup: CodeFragment[] = []
for (let i = 0; i < selectorPatterns.length; i++) {
const { selector } = selectorPatterns[i]
const selectorName = `_selector${id}_${i}`
- patternFrag.push(
+ selectorDeclarations.push(`let ${selectorName}`, NEWLINE)
+ if (i === 0) {
+ selectorSetup.push(`({ createSelector }) => {`, INDENT_START)
+ }
+ selectorSetup.push(
NEWLINE,
- `const ${selectorName} = `,
- ...genCall(`n${id}.useSelector`, [
+ `${selectorName} = `,
+ ...genCall(`createSelector`, [
`() => `,
...genExpression(selector, context),
]),
)
+ if (i === selectorPatterns.length - 1) {
+ selectorSetup.push(INDENT_END, NEWLINE, '}')
+ }
}
const blockFn = context.withId(() => {
return [
NEWLINE,
+ ...selectorDeclarations,
`const n${id} = `,
...genCall(
- helper('createFor'),
+ [helper('createFor'), 'undefined'],
sourceExpr,
blockFn,
genCallback(keyProp),
flags ? String(flags) : undefined,
+ selectorSetup.length ? selectorSetup : undefined,
// todo: hydrationNode
),
- ...patternFrag,
]
// construct a id -> accessor path map.
import { ref } from '@vue/reactivity'
import { makeRender } from './_utils'
-// @ts-expect-error
-import { createFor, createSelector, renderEffect } from '../src'
+import { createFor } from '../src'
import { nextTick } from '@vue/runtime-dom'
const define = makeRender()
-describe.todo('api: createSelector', () => {
+describe('api: createSelector', () => {
test('basic', async () => {
let calledTimes = 0
let expectedCalledTimes = 0
const index = ref(0)
const { host } = define(() => {
- const isSleected = createSelector(index)
+ let selector: (cb: () => void) => void
return createFor(
() => list.value,
item => {
const span = document.createElement('li')
- renderEffect(() => {
+ selector(() => {
calledTimes += 1
const { id } = item.value
- span.textContent = `${id}.${isSleected(id) ? 't' : 'f'}`
+ span.textContent = `${id}.${id === index.value ? 't' : 'f'}`
})
return span
},
item => item.id,
+ undefined,
+ ({ createSelector }) => {
+ selector = createSelector(() => index.value)
+ },
)
}).render()
)
expect(calledTimes).toBe((expectedCalledTimes += 2))
- list.value[2].id = 3
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0.f</li><li>1.f</li><li>3.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 1))
- })
-
- test('custom compare', async () => {
- let calledTimes = 0
- let expectedCalledTimes = 0
-
- const list = ref([{ id: 1 }, { id: 2 }, { id: 3 }])
- const index = ref(0)
-
- const { host } = define(() => {
- const isSleected = createSelector(
- index,
- // @ts-expect-error
- (key, value) => key === value + 1,
- )
- return createFor(
- () => list.value,
- item => {
- const span = document.createElement('li')
- renderEffect(() => {
- calledTimes += 1
- const { id } = item.value
- span.textContent = `${id}.${isSleected(id) ? 't' : 'f'}`
- })
- return span
- },
- item => item.id,
- )
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>1.t</li><li>2.f</li><li>3.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 3))
-
- index.value = 1
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>1.f</li><li>2.t</li><li>3.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 2))
-
- index.value = 2
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>1.f</li><li>2.f</li><li>3.t</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 2))
-
- list.value[2].id = 4
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>1.f</li><li>2.f</li><li>4.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 1))
+ // list.value[2].id = 3
+ // await nextTick()
+ // expect(host.innerHTML).toBe(
+ // '<li>0.f</li><li>1.f</li><li>3.f</li><!--for-->',
+ // )
+ // expect(calledTimes).toBe((expectedCalledTimes += 1))
})
})
) => Block,
getKey?: (item: any, key: any, index?: number) => any,
flags = 0,
+ setup?: (_: {
+ createSelector: (source: () => any) => (cb: () => void) => void
+ }) => void,
): VaporFragment => {
const _insertionParent = insertionParent
const _insertionAnchor = insertionAnchor
}
}
+ if (setup) {
+ setup({ createSelector })
+ }
+
if (flags & VaporVForFlags.ONCE) {
renderList()
} else {
insert(frag, _insertionParent, _insertionAnchor)
}
- // @ts-expect-error
- frag.useSelector = useSelector
-
return frag
- function useSelector(source: () => any): (key: any, cb: () => void) => void {
+ function createSelector(source: () => any): (cb: () => void) => void {
let operMap = new Map<any, (() => void)[]>()
let activeKey = source()
let activeOpers: (() => void)[] | undefined