TSone

响应式系统

TSone 的响应式系统允许您创建响应式状态,并在状态变化时自动更新 UI。

核心概念

响应式对象

响应式对象由 reactive 创建,会在属性访问和修改时自动追踪依赖。

副作用函数

副作用函数通过 effect 创建,会在依赖变化时重新执行。

依赖追踪

框架会在 effect 运行期间记录访问过的响应式属性。

核心 API

reactive

import { reactive } from '@geektech/tsone';

const state = reactive({
  count: 0,
  user: { name: 'John', age: 30 },
});

console.log(state.count);
state.count = 1;

effect

import { effect, reactive } from '@geektech/tsone';

const state = reactive({ count: 0 });

effect(() => {
  console.log(`Count: ${state.count}`);
});

state.count = 1;
state.count = 2;

computed

import { computed, reactive } from '@geektech/tsone';

const state = reactive({ count: 0 });
const doubleCount = computed(() => state.count * 2);

console.log(doubleCount.value);
state.count = 1;
console.log(doubleCount.value);

readonly

import { reactive, readonly } from '@geektech/tsone';

const original = reactive({ count: 0 });
const readOnlyState = readonly(original);

console.log(readOnlyState.count);
original.count = 1;

ref

import { effect, ref } from '@geektech/tsone';

const count = ref(0);

effect(() => {
  console.log(`Count: ${count.value}`);
});

count.value += 1;

响应式原理

TSone 基于 JavaScript Proxy 拦截 get/set 来完成依赖收集和派发更新。

依赖追踪过程

  • 执行 effect,并将其标记为当前活动副作用
  • 在 effect 内部读取 reactive 或 ref 的值
  • 记录依赖关系
  • 当值变化时重新调度对应 effect

高级用法

嵌套响应式对象

const state = reactive({
  user: { name: 'John', address: { city: 'New York' } },
});

effect(() => {
  console.log(`${state.user.name} lives in ${state.user.address.city}`);
});

state.user.address.city = 'Los Angeles';

数组响应式

const state = reactive({ items: ['Item 1', 'Item 2'] });

effect(() => {
  console.log(state.items.join(', '));
});

state.items.push('Item 3');
state.items[0] = 'Updated Item 1';

条件依赖

const state = reactive({ showCount: true, count: 0, message: 'Hello' });

effect(() => {
  if (state.showCount) {
    console.log(`Count: ${state.count}`);
  } else {
    console.log(state.message);
  }
});

清除副作用

import { effect, reactive, stop } from '@geektech/tsone';

const state = reactive({ count: 0 });
const runner = effect(() => {
  console.log(`Count: ${state.count}`);
});

stop(runner);

watch 侦听器

watch(source, callback, options) 侦听响应式源(getter 或 ref)的变化并执行回调,返回停止侦听的函数。回调收到新值、旧值和一个注册清理函数的 onCleanup 参数;默认随调度器批处理,同一批变化只回调一次。

import { reactive, ref, watch } from '@geektech/tsone';

const count = ref(0);

const stop = watch(count, (value, oldValue) => {
  console.log(`count: ${oldValue} -> ${value}`);
});

const state = reactive({ profile: { name: 'John' } });

watch(() => state.profile.name, (name) => {
  console.log('name changed to', name);
}, { deep: true });

stop();
  • immediate: 建立后立即执行一次回调(此时 oldValue 为 undefined)
  • deep: 深度追踪 getter 返回值嵌套属性的变化
  • sync: 变化发生时同步回调(默认随调度器批处理)

最佳实践

状态设计

  • 只把需要驱动 UI 的数据放进响应式对象
  • 根据业务模块组织状态,避免无意义的深层嵌套
  • 对复杂派生值优先使用 computed

性能优化

  • 为昂贵计算使用 computed 缓存
  • 避免在 effect 中执行重计算或副作用链式写入
  • 对不应该被写入的数据使用 readonly

常见陷阱

  • 不要直接替换整个 reactive 对象
  • 不要在 effect 内部无条件修改依赖状态
  • 嵌套对象会自动响应化,无需手动再次 reactive

与组件系统集成

class CounterComponent extends Component<object, { count: number }> {
  protected initState() {
    return { count: 0 };
  }

  protected initStyles(): void {}

  protected render(): VNode {
    return {
      tag: 'button',
      children: ['Count: '],
      listeners: { click: () => this.state.count++ },
    };
  }
}

总结

通过 reactive、effect、computed、readonly、ref 和 stop,TSone 为组件状态和独立数据模型提供了统一的响应式基础。