Ramonda

@updated

@mounted runs once. @updated runs after every commit after that, with the new DOM already in place — so it is where a component reads or corrects the page once it has changed.

The situation it is for

A long list where the reader moves the selection with the arrow keys. Each keystroke re-renders the list with a different row marked — and the newly selected row may be off screen. Scrolling it into view can only happen after the page has the new markup, because until then there is nothing at the new position to scroll to:

import { createRef } from "@ramonda/core";

class Row extends Component<{ label: string; selected: boolean }> {
  private element = createRef<HTMLLIElement>();

  @updated
  keepVisible() {
    const li = this.element.current;
    if (!this.props.selected || li === null) return;
    // The question a guard here should ask: is the DOM already how I want it? Scrolling a row
    // that is on screen is a jump the reader did not ask for.
    const box = li.getBoundingClientRect();
    if (box.top >= 0 && box.bottom <= window.innerHeight) return;
    li.scrollIntoView({ block: "nearest" });
  }

  render() {
    return (
      <li ref={this.element} className={this.props.selected ? "on" : ""}>
        {this.props.label}
      </li>
    );
  }
}

@mounted cannot do this: it runs once, and the selection moves a hundred times after that. @watchProp cannot either — it runs before the render, when the row is still drawn at its old position.

The if it always needs

@updated runs after every commit, not only the one you were waiting for. So the first line of one is almost always a guard — and the question it should ask is "is the DOM already how I want it?", not "what changed?".

Reconstructing what changed is @watchProp's job, and it does it before the render, where the answer can still affect what is drawn.

What it refuses

Anything but a method.

Options. Unlike the other three it takes none, and there is nothing to configure: a commit only happens in a browser, so env would have one possible value.

What it costs, and when not to reach for it

It runs on every commit of this component, which is the most often of the four. A state write here causes another commit, which runs it again — so a guard that can stop is not tidiness, it is what keeps it from looping.

Three things belong elsewhere:

Next

  • Lifecycle — all four moments, and why there is no post-commit @watchProp.
  • @watchProp — reacting to a prop before the render.