反应挂钩,变量未在回调中捕获

时间:2020-06-15 08:43:26

标签: javascript reactjs react-hooks

据我了解,函数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>
  );
}

1 个答案:

答案 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>
  );
}