Temel kavramlar

Durum, Bağlam ve Servisler

Bileşenin durum bayrakları, reaktif durumu ve `setState`; uygulamaya (`context`) ve servislere erişim; `build` ve `dispose`.

Durum bayrakları

Bileşen yaşam döngüsünün neresinde olduğunu bayraklarla bildirir. Bayrakları MotifJS yönetir; kodunuz okur, yazmaz.

Bayrak Ne zaman true
isInitialized Yapıcı bitince.
isConfigured Yapılandırma evresi geçince: düz Component'te yapıcıda, sınıf bileşeninde kurulumun başında.
isBuilt Bileşen kurulunca (build()).
isVisible Görünürken. motif.hide() ile false olur.
isWait Bileşen beklerken: x-wait ya da bindings.wait koşulu sürerken ve x-display koşulu false iken. Bekleyen bileşen kurulmaz.
isDisposed Serbest bırakılınca. Bundan sonra bileşenin metotları bir şey yapmaz.

x-display ile motif.hide() ayrı bayraklara dokunur: x-display koşulu false olan bileşen isWait'tir ve kurulmamış olabilir; motif.hide() ile gizlenen bileşen kurulmuştur, yalnız isVisible'ı false'tur (bkz. Görünürlük).

Bileşenin durumu

Bileşenin değişen verisi reaktif bir nesnede tutulur: sınıfta bir alan (state = reactive({ … })), fonksiyon bileşeninde yerel bir değişken, Options'ta data alanı. Bu nesneyi okuyan bağlar, nesne değişince kendiliğinden güncellenir (bkz. Bileşende durum). this.useModel(model), reactive(model) ile aynıdır.

Reaktif olmayan bir veri değiştiyse bağlar bunu kendiliğinden görmez. O durumda bağlar elle yeniden okutulur:

İkisi de bileşeni yeniden kurmaz: view() yeniden çağrılmaz, childs yuvası değişmez, yalnız bağlar değerlerini yeniden okur.

Bağlam (context) — uygulamaya erişim

Her bileşen, ebeveyn zincirini tırmanarak uygulamaya context ile ulaşır (sınıfta ve Options'ta this.context, fonksiyon bileşeninde kök bileşenin context'i); ebeveyni henüz olmayan bileşen de (yapıcıda, onInitializing'de) çalışan uygulamaya ulaşır. context, çalışan Application'ın bileşene bağlı bir görünümüdür; üyeleri uygulamanınkidir: navigate, on, fire, onRouterChanged …

context üzerinden açılan on ve onRouterChanged abonelikleri bileşenin ömrüne bağlıdır; bileşen serbest bırakılınca kendiliğinden kalkar. onLifecycle için bu geçerli değildir; dönen iptal fonksiyonunu bileşenin motif.setDisposable(off)'u ile bağlayın (sınıfta ve Options'ta this.motif, fonksiyon bileşeninde kök bileşenin motif'i). Uygulama olayları için bkz. Olaylar.

Fonksiyon bileşeninde this yoktur. Aynı işler kökün ya da bir kancanın aldığı bileşenin context'iyle (sender.context) ya da useNavigation() ile yapılır; useNavigation().navigate(adres) context.navigate ile aynı gezintiyi yapar.

Servislere erişim

DI ile kayıtlı servislere iki yoldan ulaşılır. getService her bileşende vardır: sınıf ve Options bileşeninde this.getService(T), fonksiyon bileşeninde köke yazılan bir kancanın (örneğin onConfig) aldığı sender ile sender.getService(T). FromService(T) her yerde, fonksiyon bileşeninin gövdesinde de çalışır. Singleton serviste ikisi aynı örneği verir; scoped serviste getService bileşenin kendi sağlayıcısına bağlıdır, FromService uygulamanın güncel sağlayıcısından çözer (bkz. Dependency Injection).

Not listesinin başlığı klasörün adını ve not sayısını gösterir; "Yeni not" düğmesi servisten bir not yaratır ve uygulamayı o nota götürür:

import { Component } from "@motifx/core";
import { FOLDERS, NotesService, type Folder } from "../services/notes";

export class NotesHead extends Component<HTMLDivElement, { folder: Folder }> {
  notes = this.getService(NotesService)!;

  create() {
    const note = this.notes.create();
    this.context.navigate(`/notes/${note.id}`);
  }

  override onConfigured() {
    this.class.add("list__head");
  }

  override view() {
    const { folder } = this.props;
    return (
      <>
        <h2>
          {FOLDERS[folder].title} <span class="badge">{() => String(this.notes.count(folder))}</span>
        </h2>
        <button type="button" class="button--sm accent" onclick={() => this.create()}>
          Yeni not
        </button>
      </>
    );
  }
}
import { Component, ComponentBase, motifComponent, motifFragment } from "@motifx/core";
import { FOLDERS, NotesService, type Folder } from "../services/notes";

export class NotesHead extends Component<HTMLDivElement, { folder: Folder }> {
  static override elementTag = "div";
  notes = this.getService(NotesService)!;

  create() {
    const note = this.notes.create();
    this.context.navigate(`/notes/${note.id}`);
  }

  override onConfigured() {
    this.class.add("list__head");
  }

  override view() {
    const { folder } = this.props;
    const title = motifComponent("h2", (h2: ComponentBase) => {
      const badge = motifComponent("span", (span: ComponentBase) => {
        span.class.add("badge");
        span.bindings.text(() => String(this.notes.count(folder)));
      });
      h2.controls.add(motifComponent("text", (node: ComponentBase) => node.setText(`${FOLDERS[folder].title} `)), badge);
    });
    const create = motifComponent("button", (button: ComponentBase) => {
      button.attr.add({ type: "button" });
      button.class.add("button--sm accent");
      button.motif.on("click", () => this.create());
      button.setText("Yeni not");
    });
    return motifFragment({ childs: [title, create] });
  }
}
import { FromService, useNavigation } from "@motifx/core";
import { FOLDERS, NotesService, type Folder } from "../services/notes";

export function NotesHead(props: { folder: Folder }) {
  const { folder } = props;
  const notes = FromService(NotesService)!;
  const nav = useNavigation();

  const create = () => {
    const note = notes.create();
    nav.navigate(`/notes/${note.id}`);
  };

  return (
    <div class="list__head">
      <h2>
        {FOLDERS[folder].title} <span class="badge">{() => String(notes.count(folder))}</span>
      </h2>
      <button type="button" class="button--sm accent" onclick={create}>
        Yeni not
      </button>
    </div>
  );
}
import { ComponentBase, FromService, motifComponent, useNavigation } from "@motifx/core";
import { FOLDERS, NotesService, type Folder } from "../services/notes";

export function NotesHead(props: { folder: Folder }) {
  const { folder } = props;
  const notes = FromService(NotesService)!;
  const nav = useNavigation();

  const create = () => {
    const note = notes.create();
    nav.navigate(`/notes/${note.id}`);
  };

  return motifComponent("div", (head: ComponentBase) => {
    head.class.add("list__head");
    const title = motifComponent("h2", (h2: ComponentBase) => {
      const badge = motifComponent("span", (span: ComponentBase) => {
        span.class.add("badge");
        span.bindings.text(() => String(notes.count(folder)));
      });
      h2.controls.add(motifComponent("text", (node: ComponentBase) => node.setText(`${FOLDERS[folder].title} `)), badge);
    });
    const button = motifComponent("button", (b: ComponentBase) => {
      b.attr.add({ type: "button" });
      b.class.add("button--sm accent");
      b.motif.on("click", create);
      b.setText("Yeni not");
    });
    head.controls.add(title, button);
  });
}
import { motifOptions } from "@motifx/core";
import { FOLDERS, NotesService, type Folder } from "../services/notes";

export const NotesHead = (props: { folder: Folder }) => motifOptions({
  el: "div",

  get notes() {
    return this.getService(NotesService)!;
  },

  create() {
    const note = this.notes.create();
    this.context.navigate(`/notes/${note.id}`);
  },

  onConfigured() {
    this.class.add("list__head");
  },

  view() {
    const { folder } = props;
    return (
      <>
        <h2>
          {FOLDERS[folder].title} <span class="badge">{() => String(this.notes.count(folder))}</span>
        </h2>
        <button type="button" class="button--sm accent" onclick={() => this.create()}>
          Yeni not
        </button>
      </>
    );
  },
});
import { ComponentBase, motifComponent, motifFragment, motifOptions } from "@motifx/core";
import { FOLDERS, NotesService, type Folder } from "../services/notes";

export const NotesHead = (props: { folder: Folder }) => motifOptions({
  el: "div",

  get notes() {
    return this.getService(NotesService)!;
  },

  create() {
    const note = this.notes.create();
    this.context.navigate(`/notes/${note.id}`);
  },

  onConfigured() {
    this.class.add("list__head");
  },

  view() {
    const { folder } = props;
    const title = motifComponent("h2", (h2: ComponentBase) => {
      const badge = motifComponent("span", (span: ComponentBase) => {
        span.class.add("badge");
        span.bindings.text(() => String(this.notes.count(folder)));
      });
      h2.controls.add(motifComponent("text", (node: ComponentBase) => node.setText(`${FOLDERS[folder].title} `)), badge);
    });
    const create = motifComponent("button", (button: ComponentBase) => {
      button.attr.add({ type: "button" });
      button.class.add("button--sm accent");
      button.motif.on("click", () => this.create());
      button.setText("Yeni not");
    });
    return motifFragment({ childs: [title, create] });
  },
});
import { Component } from "@motifx/core";
import { FOLDERS, NotesService } from "../services/notes";

export class NotesHead extends Component {
  static elementTag = "div";
  notes = this.getService(NotesService);

  create() {
    const note = this.notes.create();
    this.context.navigate(`/notes/${note.id}`);
  }

  onConfigured() {
    this.class.add("list__head");
  }

  view() {
    const { folder } = this.props;
    return (
      <>
        <h2>
          {FOLDERS[folder].title} <span class="badge">{() => String(this.notes.count(folder))}</span>
        </h2>
        <button type="button" class="button--sm accent" onclick={() => this.create()}>
          Yeni not
        </button>
      </>
    );
  }
}
import { Component, motifComponent, motifFragment } from "@motifx/core";
import { FOLDERS, NotesService } from "../services/notes";

export class NotesHead extends Component {
  static elementTag = "div";
  notes = this.getService(NotesService);

  create() {
    const note = this.notes.create();
    this.context.navigate(`/notes/${note.id}`);
  }

  onConfigured() {
    this.class.add("list__head");
  }

  view() {
    const { folder } = this.props;
    const title = motifComponent("h2", (h2) => {
      const badge = motifComponent("span", (span) => {
        span.class.add("badge");
        span.bindings.text(() => String(this.notes.count(folder)));
      });
      h2.controls.add(motifComponent("text", (node) => node.setText(`${FOLDERS[folder].title} `)), badge);
    });
    const create = motifComponent("button", (button) => {
      button.attr.add({ type: "button" });
      button.class.add("button--sm accent");
      button.motif.on("click", () => this.create());
      button.setText("Yeni not");
    });
    return motifFragment({ childs: [title, create] });
  }
}
import { FromService, useNavigation } from "@motifx/core";
import { FOLDERS, NotesService } from "../services/notes";

export function NotesHead(props) {
  const { folder } = props;
  const notes = FromService(NotesService);
  const nav = useNavigation();

  const create = () => {
    const note = notes.create();
    nav.navigate(`/notes/${note.id}`);
  };

  return (
    <div class="list__head">
      <h2>
        {FOLDERS[folder].title} <span class="badge">{() => String(notes.count(folder))}</span>
      </h2>
      <button type="button" class="button--sm accent" onclick={create}>
        Yeni not
      </button>
    </div>
  );
}
import { FromService, motifComponent, useNavigation } from "@motifx/core";
import { FOLDERS, NotesService } from "../services/notes";

export function NotesHead(props) {
  const { folder } = props;
  const notes = FromService(NotesService);
  const nav = useNavigation();

  const create = () => {
    const note = notes.create();
    nav.navigate(`/notes/${note.id}`);
  };

  return motifComponent("div", (head) => {
    head.class.add("list__head");
    const title = motifComponent("h2", (h2) => {
      const badge = motifComponent("span", (span) => {
        span.class.add("badge");
        span.bindings.text(() => String(notes.count(folder)));
      });
      h2.controls.add(motifComponent("text", (node) => node.setText(`${FOLDERS[folder].title} `)), badge);
    });
    const button = motifComponent("button", (b) => {
      b.attr.add({ type: "button" });
      b.class.add("button--sm accent");
      b.motif.on("click", create);
      b.setText("Yeni not");
    });
    head.controls.add(title, button);
  });
}
import { motifOptions } from "@motifx/core";
import { FOLDERS, NotesService } from "../services/notes";

export const NotesHead = (props) => motifOptions({
  el: "div",

  get notes() {
    return this.getService(NotesService);
  },

  create() {
    const note = this.notes.create();
    this.context.navigate(`/notes/${note.id}`);
  },

  onConfigured() {
    this.class.add("list__head");
  },

  view() {
    const { folder } = props;
    return (
      <>
        <h2>
          {FOLDERS[folder].title} <span class="badge">{() => String(this.notes.count(folder))}</span>
        </h2>
        <button type="button" class="button--sm accent" onclick={() => this.create()}>
          Yeni not
        </button>
      </>
    );
  },
});
import { motifComponent, motifFragment, motifOptions } from "@motifx/core";
import { FOLDERS, NotesService } from "../services/notes";

export const NotesHead = (props) => motifOptions({
  el: "div",

  get notes() {
    return this.getService(NotesService);
  },

  create() {
    const note = this.notes.create();
    this.context.navigate(`/notes/${note.id}`);
  },

  onConfigured() {
    this.class.add("list__head");
  },

  view() {
    const { folder } = props;
    const title = motifComponent("h2", (h2) => {
      const badge = motifComponent("span", (span) => {
        span.class.add("badge");
        span.bindings.text(() => String(this.notes.count(folder)));
      });
      h2.controls.add(motifComponent("text", (node) => node.setText(`${FOLDERS[folder].title} `)), badge);
    });
    const create = motifComponent("button", (button) => {
      button.attr.add({ type: "button" });
      button.class.add("button--sm accent");
      button.motif.on("click", () => this.create());
      button.setText("Yeni not");
    });
    return motifFragment({ childs: [title, create] });
  },
});

Not listesi başlığı <NotesHead folder={this.folder} /> ile yerleştirir.

Not listesi başlığı new NotesHead({ folder: this.folder }) ile yerleştirir.

Not listesi başlığı motifComponent(NotesHead, { folder: this.folder }) ile yerleştirir.

build ve dispose

Sonraki adım

Serbest bırakıldıktan sonra gelen asenkron sonucu atmak için using ile Asenkron Sonuç bölümüne geçin.