Skip to content

[labs/context] ContextProvider added after hostConnected does not work with ContextRoot #3251

@kevinpschaaf

Description

@kevinpschaaf

Which package(s) are affected?

Context (@lit-labs/context)

Description

Attaching a ContextRoot is designed to allow a ContextProvider to come into existence after a consumer requests the data.

We have a test for this by registering an element that has a ContextProvider after the consumer is registered.

However, another use case is for a ContextProvider controller to be added lazily to an element, after it is already registered/connected. The key difference here is when hostConnected runs: When calling addController on an already connected element, hostConnected will be run synchronous to that call; when calling addController during an element construction, hostConnected will be called later, when the element's connectedCallback lifecycle runs.

This difference manifests in a bug due to the fact that the ContextProvider controller's context-request listener is added after addController runs:

constructor(
protected host: ReactiveElement,
private context: T,
initialValue?: ContextType<T>
) {
super(initialValue);
this.host.addController(this);
this.attachListeners();
}

However during the hostConnected callback (which might be called synchronously to addController as mentioned above), we fire the context-provider that, when used in conjunction with ContextRoot, results in a context-request event being fired back to the provider:

hostConnected(): void {
// emit an event to signal a provider is available for this context
this.host.dispatchEvent(new ContextProviderEvent(this.context));
}

As such, the context-request event can be missed by the ContextProvider. The solution is hopefully as simple as flipping the addController() and attachListeners() lines.

Reproduction

https://lit.dev/playground/#gist=f709d0dc42035197bb2b4fc4ec65449a

Workaround

This workaround makes the above repro work as expectd:

  const hostConnected = ContextProvider.prototype.hostConnected;
  ContextProvider.prototype.hostConnected = async function() {
    await 0;
    hostConnected.call(this);
  }

Is this a regression?

No or unsure. This never worked, or I haven't tried before.

Affected versions

@lit-labs/context 0.1.3

Browser/OS/Node environment

Browser: any

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

✅ Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions