Radiant0.3.0-rc.3

@contextSelector

Use @contextSelector(...) on a field to bind it to the current context value or a selected slice of it.

When the selected value changes, the field is updated and — on a render-owning host such as RadiantElement or a render-owning RadiantController — a coalesced requestUpdate() is scheduled automatically. No empty method body. No manual this.update() call.

Options

OptionTypeDescription
contextContextThe context token to resolve
select(context) => SelectedOptional projection. Narrows the resolved value before it is written to the field
subscribebooleanWhether client-side subscriptions stay active after the first value. Defaults to true

Example

import { RadiantElement, customElement } from '@ecopages/radiant';
import { contextSelector } from '@ecopages/radiant/context';
 
import { todoContext, type Todo } from './todo-context';
 
@customElement('todo-board')
export class TodoBoard extends RadiantElement {
	@contextSelector({ context: todoContext, select: ({ todos }) => todos })
	todos: Todo[] = [];
 
	override render() {
		return (
			<ul>
				{this.todos.map((todo) => (
					<li>{todo.text}</li>
				))}
			</ul>
		);
	}
}

render() reads this.todos directly. When the todo list changes in context, the field is updated and the host rerenders automatically.

RadiantController Example

import { RadiantController } from '@ecopages/radiant';
import { contextSelector } from '@ecopages/radiant/context';
 
import { todoContext, type Todo } from './todo-context';
 
export class TodoPanelController extends RadiantController {
	@contextSelector({ context: todoContext, select: ({ todos }) => todos })
	todos: Todo[] = [];
 
	override render() {
		return (
			<ul>
				{this.todos.map((todo) => (
					<li>{todo.text}</li>
				))}
			</ul>
		);
	}
}

Full context on a field

Omit select to bind the whole context value to the field. This is the right choice when the derived view value also depends on instance state — such as a @prop — that the select function cannot access.

@customElement('insight-card')
export class InsightCard extends RadiantElement {
	@prop({ type: String }) kind: 'commits' | 'stage' | 'tempo' = 'stage';
 
	@contextSelector({ context: boardContext })
	context: BoardContext | undefined;
 
	override render() {
		let summary = 'Pending';
		if (this.context) {
			switch (this.kind) {
				case 'commits': summary = `${this.context.commits} synced`; break;
				case 'tempo':   summary = this.context.tempo; break;
				default:        summary = this.context.stage;
			}
		}
		return <p>{summary}</p>;
	}
}

The key constraint: select only receives the context value — it has no access to this. Whenever the derived value depends on instance state, bind the full context and compute in render(). Do not introduce an intermediate @state field or an @onContextUpdate callback just to copy the result.

For side effects: use @onContextUpdate

When the context change should trigger imperative work rather than a rerender, use @onContextUpdate on a method instead.

import { onContextUpdate } from '@ecopages/radiant/context';
 
@customElement('analytics-tracker')
export class AnalyticsTracker extends RadiantElement {
	@onContextUpdate({ context: cartContext, select: ({ total }) => total })
	onTotalChanged(total: number) {
		this.setAttribute('data-cart-total', String(total));
	}
}

When To Use Which

DecoratorTargetUse when
@contextSelector(...)fieldThe host should render from the current context value
@onContextUpdate(...)methodA context change should trigger imperative side effects
@consumeContext(...)fieldThe host needs the provider object to call setContext(...)

Subscribe Behavior

On the client, the field keeps receiving updates according to subscribe. During SSR, the field can also be written when an ambient provider is available.

When To Use It

  • Use @contextSelector(...) on a render-owning host field when render() should read from the current context value.
  • Use @onContextUpdate when the response is imperative work.
  • Use @consumeContext when the host needs to write to context via setContext(...).