Ramonda

RMD062 — A field read its model while a commit ran

import { Component, createRef, mounted, state, type EventOn } from "@ramonda/core";

class Terms extends Component {
  @state accepted = false;
  private box = createRef<HTMLInputElement>();

  flipped(event: EventOn<HTMLInputElement>) {
    this.accepted = event.currentTarget.checked;
  }

  @mounted
  start() {
    this.box.current?.click();   // ✗ a value set by an event, while the commit runs
  }

  render() {
    return (
      <input type="checkbox" aria-label="Terms" ref={this.box} checked={this.accepted} onchange={this.flipped} />
    );
  }
}

A field learns its model through render, and the render an edit's handler causes runs once the commit is over. The work a commit runs — render(), the constructor, @created, @mounted, @updated, @destroyed, @watchProp, @catchError — is still running when the edit arrives.

One edit from there is answered like any. The next read of the model is what goes wrong: whether the handler took the first edit or refused it is known once its render has run, so the next event in the same commit reads the model as it was — a change after a refused input reaches onchange with the text the handler refused, and a word an input method ends there is handed to oninput again although the handler took it. The edit is still answered — this is reported, not thrown.

What a field shows is state. Write it, and the commit's render shows it:

import { Component, createRef, state, type EventOn } from "@ramonda/core";

class Terms extends Component {
  @state accepted = true;                                   // ✓ known at the start
  private box = createRef<HTMLInputElement>();

  flipped(event: EventOn<HTMLInputElement>) {
    this.accepted = event.currentTarget.checked;
  }

  render() {
    return (
      <input type="checkbox" aria-label="Terms" ref={this.box} checked={this.accepted} onchange={this.flipped} />
    );
  }
}

A value learned on mount is written in @mounted — this.accepted = this.saved — and an edit that must go through the field's handler and the form around it is sent once the commit is over: queueMicrotask(() => this.box.current?.click()). A library handed the field tells you its value through its own callback, which writes state. An event handler is not a commit's work: a row whose onclick clicks its checkbox does what a <label> does.

ramonda-check reports the same edit before it ships, as field-set-by-an-event.

Next