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

如何在SubscriptionHandler实例变量变更时重渲染React函数组件?

实现点击按钮后重渲染组件并展示最新数据的方案

我正在使用以下代码,每当点击按钮时,希望重渲染OrderBookHome组件并展示SubscriptionHandler中orderBooks的最新数据,且不想在OrderBookHome中创建新的SubscriptionHandler实例,正确的实现方式是什么?


当前代码

SubscriptionHandler.js

class SubscriptionHandler {
  constructor() {
    this.orderBooks = [];
  }
  
  recenterOrderBooks = () => {
    this.orderBooks.forEach((item, idx) => {
      // 执行修改orderBooks的逻辑
    });
  };
}

const subscriptionHandler = new SubscriptionHandler();

export default subscriptionHandler;

OrderBookHome.js

import subscriptionHandler from "../../services/SubscriptionHandler";
import { Box } from '@mui/material';
import AddOrderBookForm from './AddOrderBookForm';

function OrderBookHome() {
   // 其他逻辑代码
   
   return (
     <Box display="flex" justifyContent="center">
       <AddOrderBookForm handleRecenter={subscriptionHandler.recenterOrderBooks} />
     </Box>
   );
}

export default OrderBookHome;

AddOrderBookForm.js

import { Button } from '@mui/material';

function AddOrderBookForm({...otherstates, handleRecenter}) {
   // 其他逻辑代码
   
   return (
     // 其他JSX代码
     {condition &&
        <Button onClick={handleRecenter}> Recenter Orderbooks </Button>
     }          
     // 其他JSX代码
   );
}

export default AddOrderBookForm;

正确实现方式

核心问题是:单例SubscriptionHandler的orderBooks变化不会触发React组件重渲染,需要让组件感知到数据变化并更新自身状态。我们可以给SubscriptionHandler添加订阅/发布模式,配合React的状态钩子实现。

步骤1:修改SubscriptionHandler,添加订阅通知功能

// SubscriptionHandler.js
class SubscriptionHandler {
  constructor() {
    this.orderBooks = [];
    this.subscribers = []; // 存储订阅回调函数
  }

  // 订阅数据变化
  subscribe(callback) {
    this.subscribers.push(callback);
    // 返回取消订阅的函数,用于组件卸载时清理
    return () => {
      this.subscribers = this.subscribers.filter(cb => cb !== callback);
    };
  }

  // 通知所有订阅者数据已更新(私有方法)
  #notifySubscribers() {
    // 传递数组副本,避免直接修改原引用导致的意外问题
    this.subscribers.forEach(callback => callback([...this.orderBooks]));
  }

  recenterOrderBooks = () => {
    this.orderBooks.forEach((item, idx) => {
      // 这里执行修改orderBooks的逻辑,示例:
      // item.price = 0;
    });
    // 修改完成后通知订阅者
    this.#notifySubscribers();
  };

  // 如果有其他修改orderBooks的方法,也要在修改后调用#notifySubscribers
}

const subscriptionHandler = new SubscriptionHandler();

export default subscriptionHandler;

步骤2:修改OrderBookHome,订阅数据变化并更新状态

// OrderBookHome.js
import { useState, useEffect } from 'react';
import subscriptionHandler from "../../services/SubscriptionHandler";
import { Box } from '@mui/material';
import AddOrderBookForm from './AddOrderBookForm';

function OrderBookHome() {
  // 用本地状态存储最新的orderBooks,状态变化会触发组件重渲染
  const [orderBooks, setOrderBooks] = useState(subscriptionHandler.orderBooks);

  useEffect(() => {
    // 订阅数据变化,更新本地状态
    const unsubscribe = subscriptionHandler.subscribe(newOrderBooks => {
      setOrderBooks(newOrderBooks);
    });

    // 组件卸载时取消订阅,避免内存泄漏
    return unsubscribe;
  }, []);

  // 现在可以使用orderBooks渲染最新数据了
  return (
    <Box display="flex" justifyContent="center">
      {/* 示例:渲染orderBooks列表 */}
      <div className="order-books-list">
        {orderBooks.map((book, index) => (
          <div key={index}>
            {book.symbol}: {book.price}
          </div>
        ))}
      </div>
      <AddOrderBookForm handleRecenter={subscriptionHandler.recenterOrderBooks} />
    </Box>
  );
}

export default OrderBookHome;

步骤3:AddOrderBookForm保持不变

原组件无需修改,点击按钮时会触发recenterOrderBooks,进而通知OrderBookHome更新状态并重渲染。


原理说明

  • 订阅/发布模式让SubscriptionHandler在数据变化时主动通知所有订阅的组件
  • React组件通过useState维护本地数据副本,状态更新会自动触发重渲染
  • 用useEffect管理订阅的生命周期,组件卸载时取消订阅避免内存泄漏

内容的提问来源于stack exchange,提问作者Aman Varshney

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 15:58:14