据我了解,函数Design在每次调用setRenderer时执行;并每次创建一个新的SyncEvent。但是,该变量未在eventRef.subscribe('properties'...)中捕获。为什么回调中的renderer为null,但在函数主体中确实有一个值?
export class SyncEvent {
subscriber: (value: any) => void;
subscribers = new Map<string, ((value: any) => void)[]>();
subscribe(id: string, callback: (value: any) => void) { ;
this.subscribers.set(id, [...this.subscribers.get(id) || [], callback]);
}
unsubscribe(id: string) {
this.subscribers.delete(id);
}
emit(id:string, value?: any) {
this.subscriber && this.subscriber(value);
this.subscribers.get(id)?.forEach(s => s(value));
}
}
const Design = (props: Props) => {
const eventRef = new SyncEvent();
const [renderer, setRenderer] = useState<ViewRenderer>()
const [manager] = useState(new ViewRenderer({component: PageView, isContainer: true}, eventRef))
console.log(renderer); // not null when 2nd runs
console.log(eventRef)
eventRef.subscribe('properties', (event) => {
console.log(renderer) // <--- renderer is NULL
setRenderer(renderer);
})
return (
<div className='design'>
<div className='design-main'>
{manager.renderComponent()}
</div>
<div className='design-right'>
<PropertiesViewPanel properties={properties}/>
</div>
</div>
);
}
答案 0 :(得分:1)
问题在于您直接在render方法中创建订阅,而没有在重新渲染时清除订阅。因此,由于您仅在setState中分配了一次管理者实例,因此仍使用旧的具有关闭值的注册订阅继续运行
您应该使用useEffect设置和清除订阅
const Design = (props: Props) => {
const [renderer, setRenderer] = useState<ViewRenderer>()
const [manager, setManager] = useState(null)
useEffect(() => {
const eventRef = new SyncEvent();
setManager(new ViewRenderer({component: PageView, isContainer: true}, eventRef));
eventRef.subscribe('properties', (event) => {
setRenderer(renderer);
});
return () => {
eventRef.unsubscribe('properties');
}
}, [renderer]);
return (
<div className='design'>
<div className='design-main'>
{manager && manager.renderComponent()}
</div>
<div className='design-right'>
<PropertiesViewPanel properties={properties}/>
</div>
</div>
);
}