Skip to content

Commit

Permalink
Removes ComponentRef.prototype.connected.
Browse files Browse the repository at this point in the history
This has been obsoleted by `ComponentAccessor.prototype.connected`.
  • Loading branch information
dgp1130 committed Sep 5, 2024
1 parent df1c832 commit 0671c5d
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 294 deletions.
141 changes: 0 additions & 141 deletions src/component-ref.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,147 +24,6 @@ describe('component-ref', () => {
});
});

describe('connected', () => {
it('invokes the given callback on connect', () => {
const onConnect = jasmine.createSpy<OnConnect>('onConnect');

const el = document.createElement('noop-component');
const ref = el.getComponentRef();

ref.connected(onConnect);
expect(onConnect).not.toHaveBeenCalled();

document.body.appendChild(el);
expect(onConnect).toHaveBeenCalledOnceWith();
});

it('invokes the given callback on repeated connections', () => {
const onConnect = jasmine.createSpy<OnConnect>('onConnect');

const el = document.createElement('noop-component');
const ref = el.getComponentRef();

ref.connected(onConnect);
expect(onConnect).not.toHaveBeenCalled();

// Called on first connection.
document.body.appendChild(el);
expect(onConnect).toHaveBeenCalledOnceWith();

onConnect.calls.reset();

el.remove();
expect(onConnect).not.toHaveBeenCalled();

// Called again on second connection.
document.body.appendChild(el);
expect(onConnect).toHaveBeenCalledOnceWith();
});

it('invokes the connected disposer on disconnect', () => {
const onDisconnect = jasmine.createSpy<OnDisconnect>('onDisconnect');

const el = document.createElement('noop-component');
const ref = el.getComponentRef();

ref.connected(() => onDisconnect);
expect(onDisconnect).not.toHaveBeenCalled();

document.body.appendChild(el);
expect(onDisconnect).not.toHaveBeenCalled();

el.remove();
expect(onDisconnect).toHaveBeenCalledOnceWith();
});

it('refreshes the disconnect listener on each connection', () => {
const onDisconnect1 = jasmine.createSpy<OnDisconnect>('onDisconnect1');
const onDisconnect2 = jasmine.createSpy<OnDisconnect>('onDisconnect2');

const el = document.createElement('noop-component');
const ref = el.getComponentRef();

ref.connected(jasmine.createSpy().and.returnValues(
onDisconnect1,
onDisconnect2,
));
expect(onDisconnect1).not.toHaveBeenCalled();
expect(onDisconnect2).not.toHaveBeenCalled();

// First connect.
document.body.appendChild(el);
expect(onDisconnect1).not.toHaveBeenCalled();
expect(onDisconnect2).not.toHaveBeenCalled();

// First disconnect should only call the first disconnect listener.
el.remove();
expect(onDisconnect1).toHaveBeenCalledOnceWith();
expect(onDisconnect2).not.toHaveBeenCalled();

onDisconnect1.calls.reset();

// Second connect.
document.body.appendChild(el);
expect(onDisconnect1).not.toHaveBeenCalled();
expect(onDisconnect2).not.toHaveBeenCalled();

// Second disconnect should only call the second disconnect listener.
el.remove();
expect(onDisconnect1).not.toHaveBeenCalled();
expect(onDisconnect2).toHaveBeenCalledOnceWith();
});

it('manages multiple connect callbacks', () => {
const onConnect1 = jasmine.createSpy<OnConnect>('onConnect1');
const onConnect2 = jasmine.createSpy<OnConnect>('onConnect2');

const el = document.createElement('noop-component');
const ref = el.getComponentRef();

ref.connected(onConnect1);
ref.connected(onConnect2);

expect(onConnect1).not.toHaveBeenCalled();
expect(onConnect2).not.toHaveBeenCalled();

document.body.appendChild(el);
expect(onConnect1).toHaveBeenCalledOnceWith();
expect(onConnect2).toHaveBeenCalledOnceWith();
});

it('invokes the connect callback immediately when already connected', () => {
const onConnect = jasmine.createSpy<OnConnect>('onConnect');

const el = document.createElement('noop-component');
const ref = el.getComponentRef();

document.body.appendChild(el);
expect(onConnect).not.toHaveBeenCalled();

ref.connected(onConnect);
expect(onConnect).toHaveBeenCalledOnceWith();
});

it('does not invoke the connect callback when disconnected', () => {
const onConnect = jasmine.createSpy<OnConnect>('onConnect');

const el = document.createElement('noop-component');
const ref = el.getComponentRef();

// Connect and disconnect the element.
document.body.appendChild(el);
el.remove();

// Should not be called because the element is currently disconnected.
ref.connected(onConnect);
expect(onConnect).not.toHaveBeenCalled();

// Should be called when connected.
document.body.appendChild(el);
expect(onConnect).toHaveBeenCalledOnceWith();
});
});

describe('effect', () => {
it('schedules the effect for the next animation frame', async () => {
const el = document.createElement('noop-component');
Expand Down
35 changes: 2 additions & 33 deletions src/component-ref.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Connectable, OnConnect } from './connectable.js';
import { Connectable } from './connectable.js';
import { effect } from './signals.js';
import { UiScheduler } from './signals/schedulers/ui-scheduler.js';

Expand Down Expand Up @@ -33,37 +33,6 @@ export class ComponentRef {
return await this.#scheduler.stable();
}

/**
* Sets up the given handler to be invoked whenever the component is connected
* to the DOM. If the handler returns a function, that function will be
* invoked the next time the component is disconnected. This provides a useful
* API for maintaining state which needs to be cleaned up while avoiding
* memory leaks in the component.
*
* The connect handler may be invoked multiple times if the component is
* disconnected and reconnected to the DOM.
*
* Example:
*
* ```typescript
* component('my-component', (comp) => {
* comp.connected(() => {
* console.log('I am connected!');
*
* // Optional cleanup work to be run on disconnect.
* return () => {
* console.log('I am disconnected!');
* };
* });
* });
* ```
*
* @param onConnect The function to invoke when the component is connected.
*/
public connected(onConnect: OnConnect): void {
this.#connectable.connected(onConnect);
}

/**
* Schedules the side-effectful callback to be invoked and tracks signal usage
* within it. When any dependency signal changes, the effect is re-run on the
Expand All @@ -75,7 +44,7 @@ export class ComponentRef {
* @param callback The side-effectful callback to be invoked.
*/
public effect(callback: () => void): void {
this.connected(() => {
this.#connectable.connected(() => {
return effect(callback, this.#scheduler);
});
}
Expand Down
25 changes: 12 additions & 13 deletions src/element-accessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,11 @@ describe('element-accessor', () => {
it('listens invokes the given callback when the specified event is triggered', () => {
const el = document.createElement('noop-component');
document.body.appendChild(el);
const comp = el.getComponentRef();
const host = el.getComponentAccessor();

const handler = jasmine.createSpy<(evt: Event) => void>('handler');

ElementAccessor.from(el).listen(comp, 'click', handler);
ElementAccessor.from(el).listen(host, 'click', handler);
expect(handler).not.toHaveBeenCalled();

el.click();
Expand All @@ -303,15 +303,15 @@ describe('element-accessor', () => {

it('removes event listener on disconnect', () => {
const el = document.createElement('noop-component');
const comp = el.getComponentRef();
const host = el.getComponentAccessor();

const addSpy = spyOn(el, 'addEventListener').and.callThrough();
const removeSpy = spyOn(el, 'removeEventListener').and.callThrough();

const handler = jasmine.createSpy<() => void>('handler');

// Start listening while disconnected, nothing should happen yet.
ElementAccessor.from(el).listen(comp, 'click', handler);
ElementAccessor.from(el).listen(host, 'click', handler);
expect(addSpy).not.toHaveBeenCalled();
expect(removeSpy).not.toHaveBeenCalled();

Expand Down Expand Up @@ -352,12 +352,11 @@ describe('element-accessor', () => {
</noop-component>
`);
document.body.appendChild(el);
const comp = el.getComponentRef();
const host = ElementAccessor.from(el);
const host = el.getComponentAccessor();

const handler = jasmine.createSpy<() => void>('handler');

host.query('div#first').access().listen(comp, 'click', handler);
host.query('div#first').access().listen(host, 'click', handler);

// Listen for direct events.
host.query('div#first').access().element.click();
Expand All @@ -381,11 +380,11 @@ describe('element-accessor', () => {
it('supports custom events', () => {
const el = document.createElement('noop-component');
document.body.appendChild(el);
const comp = el.getComponentRef();
const host = el.getComponentAccessor();

const handler = jasmine.createSpy<(evt: Event) => void>('handler');

ElementAccessor.from(el).listen(comp, 'custom-event', handler);
ElementAccessor.from(el).listen(host, 'custom-event', handler);

const evt = new CustomEvent('custom-event');
el.dispatchEvent(evt);
Expand All @@ -396,11 +395,11 @@ describe('element-accessor', () => {
it('propagates the `capture` option', () => {
const el = document.createElement('noop-component');
document.body.appendChild(el);
const comp = el.getComponentRef();
const host = el.getComponentAccessor();

spyOn(el, 'addEventListener').and.callThrough();

ElementAccessor.from(el).listen(comp, 'click', () => {}, {
ElementAccessor.from(el).listen(host, 'click', () => {}, {
capture: true,
});

Expand All @@ -414,11 +413,11 @@ describe('element-accessor', () => {
it('propagates the `passive` option', () => {
const el = document.createElement('noop-component');
document.body.appendChild(el);
const comp = el.getComponentRef();
const host = el.getComponentAccessor();

spyOn(el, 'addEventListener').and.callThrough();

ElementAccessor.from(el).listen(comp, 'click', () => {}, {
ElementAccessor.from(el).listen(host, 'click', () => {}, {
passive: true,
});

Expand Down
Loading

0 comments on commit 0671c5d

Please sign in to comment.