Skip to content

Commit

Permalink
feat(v2): ref value as a function (#6716)
Browse files Browse the repository at this point in the history
  • Loading branch information
Varixo authored Jul 23, 2024
1 parent 68762d5 commit a805502
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 36 deletions.
22 changes: 18 additions & 4 deletions packages/qwik/src/core/v2/client/vnode-diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,11 +605,17 @@ export const vnode_diff = (
continue;
}

if (isSignal(value)) {
if (key === 'ref') {
if (key === 'ref') {
if (isSignal(value)) {
value.value = element;
continue;
} else if (typeof value === 'function') {
value(element);
continue;
}
}

if (isSignal(value)) {
value = trackSignal(value, [
SubscriptionType.PROP_IMMUTABLE,
vNewNode as fixMeAny,
Expand Down Expand Up @@ -749,10 +755,18 @@ export const vnode_diff = (
vnode_setProp(vnode, key, value);
return;
}

if (key === 'ref') {
value.value = vnode_getNode(vnode);
return;
const element = vnode_getNode(vnode) as Element;
if (isSignal(value)) {
value.value = element;
return;
} else if (typeof value === 'function') {
value(element);
return;
}
}

vnode_setAttr(journal, vnode, key, value);
if (value === null) {
// if we set `null` than attribute was removed and we need to shorten the dstLength
Expand Down
56 changes: 56 additions & 0 deletions packages/qwik/src/core/v2/tests/ref.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { component$, useSignal, useVisibleTask$, Fragment as Component } from '@builder.io/qwik';
import { domRender, ssrRenderToDom, trigger } from '@builder.io/qwik/testing';
import { describe, expect, it } from 'vitest';

const debug = false; //true;
Error.stackTraceLimit = 100;

describe.each([
{ render: ssrRenderToDom }, //
{ render: domRender }, //
])('$render.name: ref', ({ render }) => {
describe('useVisibleTask$', () => {
it('should handle ref prop', async () => {
const Cmp = component$(() => {
const v = useSignal<Element>();
useVisibleTask$(() => {
v.value!.textContent = 'Abcd';
});
return <p ref={v}>Hello Qwik</p>;
});

const { document } = await render(<Cmp />, { debug });

if (render === ssrRenderToDom) {
await trigger(document.body, 'p', 'qvisible');
}

await expect(document.querySelector('p')).toMatchDOM(<p>Abcd</p>);
});
});

it('should execute function', async () => {
(global as any).logs = [] as string[];
const Cmp = component$(() => {
return (
<div
ref={(element) => {
(global as any).logs.push('ref function', element);
}}
></div>
);
});

const { vNode } = await render(<Cmp />, { debug });

expect(vNode).toMatchVDOM(
<Component>
<div></div>
</Component>
);

expect((global as any).logs[0]).toEqual('ref function');
expect((global as any).logs[1]).toBeDefined();
(global as any).logs = undefined;
});
});
20 changes: 0 additions & 20 deletions packages/qwik/src/core/v2/tests/use-visible-task.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -591,26 +591,6 @@ describe.each([
});
});

describe('ref', () => {
it('should handle ref prop', async () => {
const Cmp = component$(() => {
const v = useSignal<Element>();
useVisibleTask$(() => {
v.value!.textContent = 'Abcd';
});
return <p ref={v}>Hello Qwik</p>;
});

const { document } = await render(<Cmp />, { debug });

if (render === ssrRenderToDom) {
await trigger(document.body, 'p', 'qvisible');
}

await expect(document.querySelector('p')).toMatchDOM(<p>Abcd</p>);
});
});

describe('regression', () => {
it('#1717 - custom hooks should work', async () => {
const Issue1717 = component$(() => {
Expand Down
30 changes: 18 additions & 12 deletions packages/qwik/src/server/v2-ssr-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ class SSRContainer extends _SharedContainer implements ISSRContainer {
} else if (value === CLOSE_FRAGMENT) {
// write out fragment attributes
if (fragmentAttrs) {
for (let i = 0; i < fragmentAttrs.length; i++) {
for (let i = 1; i < fragmentAttrs.length; i += 2) {
const value = fragmentAttrs[i] as string;
if (typeof value !== 'string') {
fragmentAttrs[i] = String(this.addRoot(value));
Expand Down Expand Up @@ -1071,23 +1071,29 @@ class SSRContainer extends _SharedContainer implements ISSRContainer {
styleScopedId = styleId;
}

if (isSignal(value)) {
if (key === 'ref') {
const lastNode = this.getLastNode();
if (key === 'ref') {
if (isSignal(value)) {
value.value = lastNode;
continue;
} else {
value = this.trackSignalValue(value, [
immutable ? SubscriptionType.PROP_IMMUTABLE : SubscriptionType.PROP_MUTABLE,
lastNode as fixMeAny,
value,
lastNode as fixMeAny,
key,
styleScopedId || undefined,
]);
} else if (typeof value === 'function') {
value(lastNode);
continue;
}
}

if (isSignal(value)) {
const lastNode = this.getLastNode();
value = this.trackSignalValue(value, [
immutable ? SubscriptionType.PROP_IMMUTABLE : SubscriptionType.PROP_MUTABLE,
lastNode as fixMeAny,
value,
lastNode as fixMeAny,
key,
styleScopedId || undefined,
]);
}

if (key === dangerouslySetInnerHTML) {
innerHTML = String(value);
key = QContainerAttr;
Expand Down

0 comments on commit a805502

Please sign in to comment.