In a component framework, what are the two usual ways a child component signals something upward to its parent?
answer
- data down, signals up
- a function is just another input
- a declared name plus a payload
- the child reports, the parent decides
basics
~20 sEither 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.
solid answer
~40 sUpward communication has two shapes. The parent can pass a function down as an ordinary input; the child invokes it with whatever the parent needs to know, so the call is direct, synchronous, and can even return a value the child reads. Or the child can declare a named output - `item-selected` with a payload, say - and the runtime routes each emission to the handler bound where the child was used. In that shape the child cannot see what the handler does. Either way the child reports a fact (`the user picked row 7`), and the parent decides what it means; the child never writes into the parent's state. Which shape a framework prefers is a style choice - the contract underneath is the same.
go deeper
Recall both shapes: a function handed down that the child calls, or a named event the child emits and the parent handles. Data flows down as inputs, signals flow up.
Explain the difference in coupling. A called function is direct, ordered, and can return a value; a declared event is a name the runtime routes, leaving the child blind to what the handler does.
Show payload design judgment: report the fact rather than the intended action, keep the event list small enough to read as a contract, and make the component behave when nothing is bound.
Weigh the two shapes as API surface across many teams. A declared event list is discoverable and reviewable; callback inputs multiply quietly and let call sites start depending on return values.
Component frameworks fix the direction of data flow: values arrive from above as inputs and are read-only inside the component. That rule is what makes a component reusable, but it leaves a gap - something happened inside the child, and the data it concerns belongs to somebody else. **Upward signalling** fills that gap, and it comes in two shapes. ## Shape 1: a function passed down as an input The parent creates a function and hands it to the child like any other value. The child keeps no special machinery for it; when the moment arrives it calls it with the facts the parent needs. - **It is an ordinary input.** It is declared, typed and documented with the rest of them, and it can be optional with a no-op default. - **The call is direct and synchronous.** The child's call *is* the parent's handler running. Control returns to the child afterwards, so the child can read a return value - a veto, a normalised value, a promise to await. - **The channel's name is the input's name.** `onRowPick` or `notifySelection` is all the contract there is. - **The child holds a callable.** It knows a function exists; it knows nothing about the parent. ## Shape 2: a declared output event The child declares the set of events it can raise, each with a name and a payload shape. At the usage site the parent binds a handler to the names it cares about. The child emits; the runtime delivers. - **The declaration is public API.** The event list is as much part of the component's contract as its inputs, and it is listable - a reader can see everything the component can tell them. - **Delivery is indirect.** The child names a fact; the runtime finds the handler. Nothing is bound? The emission is simply not observed, and that is legal. - **It is usually fire-and-forget.** There is normally no return value to read, so the child cannot depend on what the parent did. ## How the two compare | Question | Function passed as an input | Declared output event | |---|---|---| | Where the channel is named | in the input list | in the event declaration | | What the child can learn back | the return value | usually nothing | | Is a handler guaranteed | only if the input is required | no - emitting into nothing is legal | | Coupling | the child holds a callable | the child names a fact | | Discoverability | mixed in with data inputs | a separate, listable contract | ## What both refuse to do 1. **Neither lets the child write the owner's state.** The child produces a signal; the write happens in the owner's code. That is the whole point - two writers for one value is how state bugs start. 2. **Neither makes the child the decision-maker.** "The user picked row 7" is a fact. "Open the detail panel" is a decision, and it belongs to the parent, which may do something else entirely on another screen. 3. **Neither guarantees an audience.** A reusable component must behave sensibly when nobody is listening. ## Designing the payload and the name - **Report what happened, not what should happen.** `item-selected` with the item beats `open-detail`; the first survives reuse, the second hard-codes one caller's behaviour into the child. - **Send the minimum the parent cannot derive.** Handing over the child's whole internal state leaks implementation detail that becomes impossible to change later. - **One meaning per channel.** A single `changed` event with a discriminator field inside is a contract every caller has to decode. - **Name consistently.** A past-tense name reads as a notification; an imperative one reads as a command the child is issuing, which inverts the ownership rule. ## What interviewers listen for The answer they want is short - a function called, or a named event emitted - followed by the reason: the child reports, the owner decides, and inputs stay read-only. Candidates who describe the child reaching into the parent, or who cannot say who owns the value after the signal, are describing two-way data flow without knowing it. Being able to say which shape you would pick, and why - a return value needed, versus a contract you want visible in the component's declared API - is what separates a rehearsed answer from an understood one.
- Why should an upward event carry a fact rather than an instruction?Because an instruction bakes one caller's behaviour into the child. `item-selected` can be reused by a screen that filters, one that navigates and one that only logs; `open-detail-panel` forces every caller into the first behaviour or forces the child to be rewritten. Facts keep the decision where the state lives.
- What does the child gain from the shape where it calls a function directly?A return value and ordering. The call runs the parent's code inside the child's own frame, so the child can read what came back - a rejection, a normalised value, something to await - and knows the handler finished before it continues. An emitted event usually gives back nothing.
- Is it a problem if nothing is bound to a declared output event?No. A reusable component must work when a caller ignores an event it does not need, so emitting into nothing has to be legal and silent. What is a problem is a component that only functions correctly if a particular handler exists - then the channel should be a required input, not an optional event.
saying these in an interview costs you the question
- Says the child updates the parent's state directly when the user acts
- Emits an event with no payload and expects the parent to guess what happened
- Treats a declared output name as an internal detail rather than public contract
- Cannot say who decides what the signal means
- Thinks a function passed down is special machinery, not an ordinary input