You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Astro中改写Preact函数组件为类组件遇signal失效问题

问题分析

你的类组件存在两个核心问题,导致点击按钮无反应且signal不生效:

  1. 未渲染count值:原函数组件会展示count的当前状态,但你的类组件render方法里漏掉了这部分,即便signal值变化也无法直观看到。
  2. 类组件未追踪signal变化:Preact函数组件会自动追踪signal依赖并在值变化时重渲染,但类组件没有这个自动机制,需要手动订阅signal的更新事件来触发组件重渲染。
修正后的类组件代码
import { Component } from 'preact';
import type { Signal } from '@preact/signals';

type CounterProps = {
  children: Preact.ReactNode;
  count: Signal<number>;
};

export default class Counter extends Component<CounterProps> {
  private unsubscribe?: () => void;

  constructor(props: CounterProps) {
    super(props);
    this.add = this.add.bind(this);
    this.subtract = this.subtract.bind(this);
  }

  componentDidMount() {
    // 订阅signal变化,值改变时触发组件重渲染
    this.unsubscribe = this.props.count.subscribe(() => {
      this.forceUpdate();
    });
  }

  componentWillUnmount() {
    // 组件卸载时取消订阅,避免内存泄漏
    this.unsubscribe?.();
  }

  add() {
    this.props.count.value++;
  }

  subtract() {
    this.props.count.value--;
  }

  render() {
    const { children, count } = this.props;
    return (
      <>
        <div class="counter">
          <button onClick={this.subtract}>-</button>
          <pre>{count}</pre> {/* 显示count当前值,Preact会自动解包signal */}
          <button onClick={this.add}>+</button>
        </div>
        <div class="counter-message">{children}</div>
      </>
    );
  }
}
关键修复点说明
  • 添加signal订阅:在componentDidMount生命周期中调用count.subscribe(),当signal值变化时,通过this.forceUpdate()强制组件重渲染,确保UI同步更新。
  • 取消订阅:在componentWillUnmount中执行订阅返回的取消函数,防止组件卸载后仍监听signal导致内存泄漏。
  • 补全count渲染:在render方法中添加<pre>{count}</pre>,展示当前count值。
  • 类型优化:定义明确的CounterProps类型替换any,提升代码可读性和类型安全性。

内容的提问来源于stack exchange,提问作者Jeanluca Scaljeri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 17:52:58