skip to content

Component Model

One instance's contract with the tree around it: it is created and torn down, parameterized from above, signals upward, takes content and ambient values, and reaches host nodes only by escape hatch.

on this pageshow

explore

questions

page 1 of 2

In a component tree, what is an ancestor-provided value and what problem does it solve?

level: juniorimportance: must knowfreq 72%

answer

  1. ambient, not threaded
  2. one provider, whole subtree
  3. read at the point of use
  4. nearest ancestor resolves it
  5. price: dependency is invisible

basics

~20 s

A value an ancestor publishes to its whole subtree so any descendant can read it where it is used, instead of every component on the path accepting and forwarding an input it does not need.

solid answer

~40 s

Provision has two halves. An ancestor declares that, for its subtree, some agreed key carries some value; a descendant reads that key, and the runtime resolves it by walking up from the reader to the nearest ancestor that provides it. That removes the threading problem: the components in between no longer accept, declare and forward data they never use, and a consumer keeps working wherever it is moved inside the subtree. It suits ambient values many components read and few write - the visual theme, the display locale, the signed-in user, a configured data client. The price is implicitness: the dependency no longer appears in the consumer's inputs, and the consumer cannot render outside a provider without falling back to a default.

go deeper

for a junior

Recall the two halves: an ancestor provides a value for its subtree, and a descendant reads it where it is used. Be able to name one honest use, such as the theme or the display locale.

for a middle

Explain resolution - the read walks up from the consumer to the nearest providing ancestor - and why nothing mounted outside that subtree can see the value at all.

for a senior

Show judgment about membership: which ambient values earn a place in the channel, and how you keep a consumer diagnosable when its dependency is not in its input list.

for a principal

Weigh the hidden coupling. Ambient dependencies do not appear in a component's contract, so what the tree provides and at what scope becomes an architectural decision that needs an owner.

A component tree moves data downward through inputs: a parent supplies values, a child reads them, and that is the whole contract between the two. Ancestor provision is the escape hatch for the case where that contract is the wrong shape - when the component that needs a value sits far below the component that has it. ## The threading problem If a leaf five levels down needs a value the root holds, every component on the path must accept it, declare it and hand it on, even though none of them uses it. The costs are concrete: - **Contracts inflate.** Each intermediate component's input list grows with parameters it only forwards, and each is a name, a shape and a default to maintain. - **Edits ripple.** Adding one value to a leaf touches every component between it and the owner; removing it touches them all again. - **Reuse narrows.** An intermediate can no longer be used where the forwarded value is unavailable, because its contract now demands it. - **Moving the consumer is expensive.** Relocating the leaf into another branch means re-threading the value along a different path. ## What provision actually is Provision replaces the path with a scope, and it has two halves: 1. **A provider** placed at some node declares: *for my subtree, this key carries this value*. The key is a shared token - an identity both sides agree on, not a variable name that happens to match. 2. **A read** somewhere below asks for that key. The runtime resolves it by walking upward from the reading component through its ancestors and taking the first one that provides that key. Two properties follow from resolution being an upward walk: - The scope is **structural**. Who can read the value is decided by tree position at run time, not by file layout, module boundaries or declaration order. - The scope is **bounded by the subtree**. A sibling of the provider, an ancestor of it, or anything mounted outside it cannot see the value; those reads fall back to a default or fail. | | explicit threading | ancestor provision | |---|---|---| | how the value arrives | each level accepts it and passes it on | read directly where it is used | | who must know about it | every component on the path | the provider and the reader | | visible in the contract | yes, as a declared input | no, it is ambient | | reach | exactly the path you wrote | the provider's whole subtree | | moving a consumer | re-thread along the new path | works anywhere under the provider | ## What belongs in the channel The pattern pays off for values **read in many places, written in few, and changing slowly relative to how often components render**: - the visual theme and its design tokens; - the display locale and the formatting rules derived from it; - the signed-in user or the current session; - a configured transport or data client the whole subtree talks through; - a logger, or a reader for feature switches. It pays off badly for a value that travels one or two levels - pass it - for a parameter that belongs to a single parent-child relationship, and for high-frequency data, because what a change costs there is decided by the runtime rather than by the pattern. ## The price you pay Provision buys brevity with implicitness: - The consumer's dependency is not in its contract. Reading the component tells you what it renders, not which ambient values it requires. - The consumer cannot render outside a provider. Placed in the wrong branch it quietly takes a default instead of failing where the mistake is. - "Where did this value come from?" becomes a question about run-time tree position, which is harder to answer than following an input one level up. Frameworks also differ sharply in what a change to a provided value costs. Where the channel carries one opaque value whose changes are detected by comparing identity, every consumer in the subtree is notified when anything inside it changes. Where the provided value is a fine-grained reactive cell, only the computations that actually read it are notified. Where you provide a plain collaborator object, provision propagates nothing at all: it hands out a reference, and notification is arranged separately. ## Reading the pattern as injection Seen from above, provision is dependency injection expressed through the tree: an ancestor decides which implementation its subtree gets, and the descendant names only the capability it needs, never the construction. That is why the same mechanism carries both data a subtree reads and collaborators it calls, and why the useful question about a provided value is usually *who chooses this, and for how wide a scope*, rather than *how do I read it*.

  • Why is provision a poor fit for a value that only travels one or two levels down?
    Because the cost it removes is small and the cost it adds is not. Two explicit inputs are visible in the contract, checked at the call site and trivial to trace. An ambient value saves almost no typing here, while making the child unrenderable without a provider above it and hiding its real dependency from anyone reading it.
  • Does provision change where the value lives?
    No. The value still lives wherever the provider put it - usually state the providing component owns, or an object created during its setup. Provision changes only who may read it: it publishes a reference to the subtree. A read does not copy the value, so descendants see whatever the provider currently holds.

saying these in an interview costs you the question

  • Thinks a provided value is a global readable anywhere in the app
  • Says intermediate components still declare and forward it automatically
  • Reaches for provision for a value that travels one or two levels
  • Believes a sibling of the provider can read the provided value
  • Puts every piece of application data into the ambient channel
open as a page

In a component framework, what does a default content slot do, and who owns the content that lands in it?

level: juniorimportance: must knowfreq 78%

basics

~20 s

A default content slot is a placeholder where a component renders whatever content its caller passed between its tags. The caller writes and owns that content; the component only chooses where, and whether, it appears.

open as a page

What is a host-node reference in a component framework, and when is it safe to read?

level: juniorimportance: must knowfreq 72%

basics

~20 s

A host-node reference is a container the framework fills with the real node it created for a rendered element, so code can focus, scroll or measure it. It is empty while output is described and filled once that output is committed.

open as a page

In a component framework, what are a component's declared inputs, and why must the child treat them as read-only?

level: juniorimportance: must knowfreq 85%

basics

~20 s

Declared inputs are the named values a parent passes into a child to parameterize it. The parent owns each one and re-supplies it every render, so the child only reads: a write there never reaches the owner.

open as a page

In a component framework, what is the difference between a component's definition, a live instance, and the output it produces?

level: juniorimportance: must knowfreq 76%

basics

~20 s

A definition is the reusable recipe: a function, a class or a compiled template. An instance is one live copy created where that definition is used, owning its own state. The output is the description the instance produces each update.

open as a page

In a component framework, what are the two usual ways a child component signals something upward to its parent?

level: juniorimportance: must knowfreq 78%

basics

~20 s

Either the parent passes a function down as an input and the child calls it, or the child declares a named output event that the parent binds a handler to. Both leave the state itself owned by the parent.

open as a page

When nested ancestors provide the same value, which one does a descendant read, and what should a missing provider do?

level: middleimportance: must knowfreq 64%

basics

~20 s

The nearest providing ancestor above the reader wins, so a closer provider overrides an outer one for its subtree only. With no provider above, the read yields a declared default, or should fail loudly when no sane default exists.

open as a page

Two components call the same reusable stateful logic unit; what do they share, and what does each get its own copy of?

level: middleimportance: must knowfreq 72%

basics

~10 s

They share the code, not the data. Each call site gets its own state, derived values, effects and cleanup, owned by the calling component instance, so one caller's updates never reach the other's copy.

open as a page

When a component renders a subtree through a portal, what changes about that subtree and what stays the same?

level: middleimportance: must knowfreq 62%

basics

~20 s

A portal changes only where the subtree's host output is attached — a container near the root, past clipping and stacking ancestors. Its place in the component tree is unchanged, so provided values, state and framework-level events follow the original parent.

open as a page

Across a component instance's creation, update and teardown phases, which work belongs in each and why?

level: middleimportance: must knowfreq 70%

basics

~20 s

Creation runs work that must happen once per instance - initial state, acquisitions, and the registration of their releases - and produces the first output. Updates only derive output from current inputs and state. Teardown runs the registered releases.

open as a page

Why does an event emitted by a deep child component not reach a distant ancestor the way a host event bubbles?

level: middleimportance: must knowfreq 58%

basics

~10 s

Because a component output resolves at its binding site: emitting invokes the handler bound where that child was used. The component tree carries no propagation path, so nothing continues upward on its own.

open as a page

In a component framework, what does a two-way binding on a child component's value actually expand to?

level: middleimportance: must knowfreq 66%

basics

~20 s

It is sugar for a pair: an input carrying the current value down, plus an output the child raises when it wants a different one, with the write back into the owner's state generated for you.

open as a page

A child mutates a field of an object it received as an input. What breaks, and why do declared types miss it?

level: seniorimportance: must knowfreq 55%

basics

~20 s

The child and the owner hold the same object, so a field write changes the owner's data with no notification, and readers disagree afterwards. Declared types describe shape, not writability, and a check runs when the value arrives, not on every later write.

open as a page

What must a wrapper component forward so that callers of the component it wraps cannot tell the wrapper is there?

level: middleimportance: should knowfreq 48%

basics

~20 s

Everything it does not consume: inputs and attributes it does not recognise, the caller's event bindings, projected content in the same named regions, and a handle to the underlying element. The wrapper adds only its own behaviour.

open as a page

When projected content needs a value only the receiving component has, such as the current row, what does a scoped slot do?

level: middleimportance: should knowfreq 52%

basics

~10 s

A scoped slot makes projected content a parameterised block: the receiving component invokes it, once or once per item, passing the values only it knows, while the caller still writes and owns the markup.

open as a page

Why would a component publish a narrow imperative handle instead of handing callers its host node?

level: middleimportance: should knowfreq 52%

basics

~20 s

An imperative handle is a small object of named operations a component publishes — focus, reset, scroll to a row. It keeps the component's internal nodes and structure private, so the markup can be rewritten without breaking any caller.

open as a page

How does a component declare an input as required, optional or defaulted, and where is each rule enforced?

level: middleimportance: should knowfreq 60%

basics

~20 s

An input declaration states the name, whether a value must be supplied, and what stands in when it is absent. Required-ness is checked either at build time or at runtime; a default applies only when the caller omits the input.

open as a page

Why must an entering component's first output carry a start state that changes to the end state only on a later frame?

level: middleimportance: should knowfreq 38%

basics

~20 s

A transition interpolates between two observed values. An element attached already in its end state gives the host nothing to animate from, so the first output commits the start state and a later frame moves it to the end state.

open as a page

Why should a component instance register the release of everything it acquires with its own scope, rather than at the site that removes it?

level: middleimportance: should knowfreq 58%

basics

~20 s

Because an instance can leave several ways - removed, replaced at the same position, carried off with an ancestor, discarded mid-update - and only the instance knows what it acquired. Registration makes cleanup run on every path.

open as a page

What do you gain by declaring behaviour such as prevent-default or run-once on an event binding rather than in the handler?

level: middleimportance: should knowfreq 42%

basics

~20 s

The declaration is data the framework reads before your code runs, so it can act, skip the call entirely, or register the listener the host needs - and the handler body stays about your domain rather than plumbing.

open as a page

What does a framework gain by handing handlers a normalized wrapper over the host event, and what does it cost?

level: middleimportance: should knowfreq 48%

basics

~20 s

A wrapper gives handlers one uniform event shape across host and browser differences, plus a seam the framework controls. The cost is a second object: whatever it omits needs the underlying event, and its controls act on the framework's layer.

open as a page

For an ancestor-provided value holding frequently changing data, what decides how costly each change is?

level: seniorimportance: should knowfreq 54%

basics

~20 s

The runtime's propagation granularity, not the pattern. A coarse channel notifies every consumer in the subtree on any change; a provided fine-grained reactive value notifies only the computations that read the changed part; a provided plain collaborator notifies nobody.

open as a page

When the ancestor that provides a value is torn down and created again, what happens to the value its descendants read?

level: seniorimportance: should knowfreq 46%

basics

~20 s

The value's lifetime is the provider instance's lifetime: a new provider instance means a freshly created value, with none of the old one's accumulated state, caches or in-flight work. Descendants are torn down with it and rebuild everything derived.

open as a page

A component now sits under five wrappers added one per variation; how do you decide between projecting content, wrapping, and extracting a reusable unit?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Match the tool to what varies: project content when the difference is markup, wrap when the difference is behaviour around a whole subtree, and extract a reusable stateful unit when the difference is state and effects several components need separately.

open as a page

How do you wrap a third-party imperative widget that builds and mutates its own host nodes inside a declaratively rendered component?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Render one empty container the framework never fills, construct the widget onto it after commit, translate input changes into the widget's own update calls, forward its callbacks upward, and dispose it on teardown. The container's interior belongs to the widget.

open as a page

A removed component must animate out first. What does the runtime have to defer, and what breaks if the animation never reports finished?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Logical removal and physical teardown split apart: the instance and its output stay alive, marked as leaving, until something signals the animation finished. If that signal never arrives, teardown never runs and every removal strands a copy.

open as a page

Why can a child component not treat a change in the handler it received as a signal that its caller changed something?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Handler identity reflects the runtime's execution model, not the caller's intent. Where the component body re-runs, a fresh function crosses the boundary every update; where the body runs once, one reference is passed for the instance's life.

open as a page

How do you govern what a large codebase provides ambiently through the component tree, and what does over-use cost?

level: principalimportance: should knowfreq 40%

basics

~20 s

Admit a value when many components read it, few write it, it changes slowly, and it is genuinely ambient to a whole subtree. Over-use hides each component's real dependencies and leaves nothing renderable without a scaffold of providers above it.

open as a page

As a lead, how do you decide which host-node escape hatches are legitimate across a large component codebase?

level: principalimportance: should knowfreq 44%

basics

~20 s

Sort by what the code reads and writes. Commands the declarative layer cannot express — focus, scroll, selection, playback, measurement, handing a node to a widget — are legitimate. Anything that writes displayed output or decides a render is refused.

open as a page

A value is threaded as an input through five components that only forward it; what does that cost, and how do you choose a remedy?

level: principalimportance: should knowfreq 45%

basics

~20 s

Each forwarding level pays a cost: its contract advertises a value it never uses, and every rename edits every level. The remedies, restructuring the composition, providing the value to a subtree, or keeping it outside the tree, are chosen by reach, lifetime and discoverability.

open as a page

showing 1–30 of 31