Await Effect

Await Effect demo built with Expressive MVC - the complete source below runs as an editable sandbox when JavaScript is enabled.

App.tsx

import './App.css';

import Button from './common/Button';
import { Component, set } from '@expressive/mvc';

export default () => (
  <div className="container">
    <h1>Await an Effect</h1>
    <p>
      The function an effect returns can also be awaited: it stops the effect
      and yields the latest value. <code>send()</code> awaits a projection of{' '}
      <code>link</code> - before the link exists the await waits for it, after
      that it resolves at once. No ready flag, no suspense boundary.
    </p>
    <Invite />
    <small>
      Only an async effect yields a value. A sync effect's return stays a
      cleanup, so awaiting one resolves <code>undefined</code>.
    </small>
  </div>
);

class Invite extends Component {
  // No value until assigned - reading `link` before then suspends.
  link = set<string>();
  status = 'Not sent';

  protected new() {
    const timer = setTimeout(() => {
      this.link = 'https://expressive.dev/join/7f3a';
    }, 2000);

    return () => clearTimeout(timer);
  }

  async send() {
    this.status = 'Waiting for the link…';

    const link = await this.get(async ($) => $.link);

    this.status = `Sent ${link}`;
  }

  render() {
    return (
      <>
        <Button primary onClick={this.send}>
          Send invite
        </Button>
        <p className="result">{this.status}</p>
      </>
    );
  }
}

App.css

.result {
  font-size: var(--t-lg);
  color: var(--fg);
}