Question presented to candidate:
"Our codebase has about forty effect() calls and a few of them keep causing stale values and one froze a page. Explain what effect() actually does in Angular, when it runs, and which of those forty you would delete."
What a strong answer should cover:
effect()registers a function that re-runs whenever a signal it read last time changes, and exists for side effects: syncing signal state out to something that is not a signal (DOM APIs, storage, logging, a third-party widget).- Timing: effects are scheduled, not synchronous. Several
set()calls in one handler produce one run with the final value. Component effects run during change detection before that component's template refreshes; root effects (created outside the component tree) run first, as part of the app tick. - It needs an injection context (or an
injectoroption) and is destroyed with its owner;onCleanupcancels work from the previous run. - When NOT to use it: deriving state (use
computed()), resettable derived state (uselinkedSignal()), copying one signal into another, loading data (useresource()/httpResource()/rxResource()), DOM reads after render (useafterRenderEffect()/afterNextRender()). - An effect that writes a signal it also reads can loop forever; Angular does not stop it.
untracked()to read without subscribing;allowSignalWritesis deprecated because writes are now allowed.
Clarifying questions expected:
- "Are the stale values coming from effects that copy one signal into another?"
- "Are these effects in components or in root services? Their timing differs."
Code / implementation expected: Yes β one legitimate effect with cleanup, and the same derived value written as an effect versus computed()/linkedSignal().