umbraco-state-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Umbraco State Management

Umbraco 状态管理

What is it?

什么是状态管理?

States in Umbraco are containers for reactive values that enable communication across component instances using the Observable pattern. An Umbraco State is a container for a value that you can create Observables from, which allows multiple observers to subscribe and automatically receive updates when the state changes. This pattern is particularly useful for sharing data between contexts and elements without tight coupling.
Umbraco中的状态是响应式值的容器,它使用Observable模式实现组件实例之间的通信。Umbraco State是一个值容器,你可以从中创建Observables,允许多个观察者订阅,并在状态更改时自动接收更新。这种模式在无需紧密耦合的情况下在上下文和元素之间共享数据时特别有用。

Documentation

文档参考

Workflow

工作流程

  1. Fetch docs - Use WebFetch on the URLs above
  2. Ask questions - What type of state? Who observes? Where to provide observable?
  3. Generate code - Implement state with observables based on latest docs
  4. Explain - Show what was created and how observation works
  1. 获取文档 - 使用WebFetch访问上述URL
  2. 提出问题 - 是什么类型的状态?谁来观察?在哪里提供observable?
  3. 生成代码 - 根据最新文档使用observables实现状态
  4. 解释说明 - 展示创建的内容以及观察机制如何工作

Minimal Examples

极简示例

Basic State Usage

基础状态使用

typescript
import { UmbStringState } from '@umbraco-cms/backoffice/observable-api';

// Create a state with initial value
const myState = new UmbStringState('initial value');

// Create an observable from the state
const myObservable = myState.asObservable();

// Observe the state (fires immediately and on changes)
this.observe(myObservable, (value) => {
  console.log('Current value:', value);
});

// Update the state (all observers notified)
myState.setValue('updated value');
typescript
import { UmbStringState } from '@umbraco-cms/backoffice/observable-api';

// Create a state with initial value
const myState = new UmbStringState('initial value');

// Create an observable from the state
const myObservable = myState.asObservable();

// Observe the state (fires immediately and on changes)
this.observe(myObservable, (value) => {
  console.log('Current value:', value);
});

// Update the state (all observers notified)
myState.setValue('updated value');

State in Context Pattern

上下文模式中的状态

typescript
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbNumberState } from '@umbraco-cms/backoffice/observable-api';

export class MyContext extends UmbContextBase<MyContext> {
  // Private state
  #counter = new UmbNumberState(0);

  // Public observable (readonly)
  readonly counter = this.#counter.asObservable();

  increment() {
    this.#counter.setValue(this.#counter.getValue() + 1);
  }

  decrement() {
    this.#counter.setValue(this.#counter.getValue() - 1);
  }
}
typescript
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbNumberState } from '@umbraco-cms/backoffice/observable-api';

export class MyContext extends UmbContextBase<MyContext> {
  // Private state
  #counter = new UmbNumberState(0);

  // Public observable (readonly)
  readonly counter = this.#counter.asObservable();

  increment() {
    this.#counter.setValue(this.#counter.getValue() + 1);
  }

  decrement() {
    this.#counter.setValue(this.#counter.getValue() - 1);
  }
}

Element Observing Context State

元素观察上下文状态

typescript
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { MY_CONTEXT } from './my-context.js';

export class MyElement extends UmbLitElement {
  @state()
  private _count = 0;

  constructor() {
    super();

    this.consumeContext(MY_CONTEXT, (context) => {
      // Observe the counter state from context
      this.observe(
        context.counter,
        (count) => {
          this._count = count;
        },
        '_countObserver'
      );
    });
  }

  render() {
    return html`
      <div>Count: ${this._count}</div>
    `;
  }
}
typescript
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { MY_CONTEXT } from './my-context.js';

export class MyElement extends UmbLitElement {
  @state()
  private _count = 0;

  constructor() {
    super();

    this.consumeContext(MY_CONTEXT, (context) => {
      // Observe the counter state from context
      this.observe(
        context.counter,
        (count) => {
          this._count = count;
        },
        '_countObserver'
      );
    });
  }

  render() {
    return html`
      <div>Count: ${this._count}</div>
    `;
  }
}

Different State Types

不同的状态类型

typescript
import {
  UmbStringState,
  UmbNumberState,
  UmbBooleanState,
  UmbArrayState,
  UmbObjectState
} from '@umbraco-cms/backoffice/observable-api';

// String state
const name = new UmbStringState('John');

// Number state
const age = new UmbNumberState(25);

// Boolean state
const isActive = new UmbBooleanState(true);

// Array state
const items = new UmbArrayState(['item1', 'item2']);

// Object state
const user = new UmbObjectState({ name: 'John', age: 25 });
typescript
import {
  UmbStringState,
  UmbNumberState,
  UmbBooleanState,
  UmbArrayState,
  UmbObjectState
} from '@umbraco-cms/backoffice/observable-api';

// String state
const name = new UmbStringState('John');

// Number state
const age = new UmbNumberState(25);

// Boolean state
const isActive = new UmbBooleanState(true);

// Array state
const items = new UmbArrayState(['item1', 'item2']);

// Object state
const user = new UmbObjectState({ name: 'John', age: 25 });

Observable Parts (Derived State)

Observable 片段(派生状态)

typescript
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';

const itemsState = new UmbArrayState(['apple', 'banana', 'cherry']);

// Observe just the first item
const firstItem = itemsState.asObservablePart(data => data?.[0]);

// Observe just the count
const itemCount = itemsState.asObservablePart(data => data.length);

// Use in element
this.observe(firstItem, (first) => {
  console.log('First item:', first);
});

this.observe(itemCount, (count) => {
  console.log('Total items:', count);
});
typescript
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';

const itemsState = new UmbArrayState(['apple', 'banana', 'cherry']);

// Observe just the first item
const firstItem = itemsState.asObservablePart(data => data?.[0]);

// Observe just the count
const itemCount = itemsState.asObservablePart(data => data.length);

// Use in element
this.observe(firstItem, (first) => {
  console.log('First item:', first);
});

this.observe(itemCount, (count) => {
  console.log('Total items:', count);
});

Array State Operations

数组状态操作

typescript
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';

const listState = new UmbArrayState<string>([]);

// Add item
listState.setValue([...listState.getValue(), 'new item']);

// Remove item
listState.setValue(
  listState.getValue().filter(item => item !== 'old item')
);

// Clear all
listState.setValue([]);

// Get current value
const current = listState.getValue();
typescript
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';

const listState = new UmbArrayState<string>([]);

// Add item
listState.setValue([...listState.getValue(), 'new item']);

// Remove item
listState.setValue(
  listState.getValue().filter(item => item !== 'old item')
);

// Clear all
listState.setValue([]);

// Get current value
const current = listState.getValue();

Complete Context Example

完整上下文示例

typescript
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbStringState, UmbArrayState } from '@umbraco-cms/backoffice/observable-api';

export class TodoContext extends UmbContextBase<TodoContext> {
  #title = new UmbStringState('My Todo List');
  #todos = new UmbArrayState<string>([]);

  readonly title = this.#title.asObservable();
  readonly todos = this.#todos.asObservable();
  readonly todoCount = this.#todos.asObservablePart(data => data.length);

  setTitle(value: string) {
    this.#title.setValue(value);
  }

  addTodo(todo: string) {
    this.#todos.setValue([...this.#todos.getValue(), todo]);
  }

  removeTodo(todo: string) {
    this.#todos.setValue(
      this.#todos.getValue().filter(t => t !== todo)
    );
  }
}
typescript
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbStringState, UmbArrayState } from '@umbraco-cms/backoffice/observable-api';

export class TodoContext extends UmbContextBase<TodoContext> {
  #title = new UmbStringState('My Todo List');
  #todos = new UmbArrayState<string>([]);

  readonly title = this.#title.asObservable();
  readonly todos = this.#todos.asObservable();
  readonly todoCount = this.#todos.asObservablePart(data => data.length);

  setTitle(value: string) {
    this.#title.setValue(value);
  }

  addTodo(todo: string) {
    this.#todos.setValue([...this.#todos.getValue(), todo]);
  }

  removeTodo(todo: string) {
    this.#todos.setValue(
      this.#todos.getValue().filter(t => t !== todo)
    );
  }
}

Key Concepts

核心概念

State: Container for a value (private, mutable)
Observable: Subscription hook created from state (public, readonly)
Observer: Function that reacts to state changes via
observe()
State Types:
  • UmbStringState
    - text values
  • UmbNumberState
    - numeric values
  • UmbBooleanState
    - boolean flags
  • UmbArrayState
    - collections
  • UmbObjectState
    - complex objects
  • UmbClassState
    - class instances
Observable Parts: Derived observables that only update when mapped value changes
Best Practice: Keep states private, expose observables publicly
Use Cases:
  • Sharing data between context and elements
  • Reactive UI updates
  • Cross-component communication
  • Derived/computed values
That's it! Always fetch fresh docs, keep examples minimal, generate complete working code.
State:值的容器(私有、可变)
Observable:从状态创建的订阅钩子(公开、只读)
Observer:通过
observe()
响应状态变化的函数
状态类型:
  • UmbStringState
    - 文本值
  • UmbNumberState
    - 数值
  • UmbBooleanState
    - 布尔标记
  • UmbArrayState
    - 集合
  • UmbObjectState
    - 复杂对象
  • UmbClassState
    - 类实例
Observable Parts:仅在映射值更改时更新的派生observables
最佳实践:保持状态私有,公开observables
使用场景:
  • 在上下文和元素之间共享数据
  • 响应式UI更新
  • 跨组件通信
  • 派生/计算值
就是这样!请务必获取最新文档,保持示例简洁,生成完整可运行的代码。