如何在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
相关产品推荐
相关产品推荐

