Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Event Design #309

Open
MrWindlike opened this issue Feb 25, 2022 · 2 comments
Open

Proposal: Event Design #309

MrWindlike opened this issue Feb 25, 2022 · 2 comments
Labels
feature New feature or request runtime about meta-ui runtime

Comments

@MrWindlike
Copy link
Contributor

Overview

Currently, the ability to communicate between components is supported by the runtime module, but the event handlers are generated by event traits when the state changes.

It's would bring some problems:

  • The parameters for event handlers aren't real-time
  • The codes of event implementation doesn't put together

Proposal

If want to fix the first problem, it should generate the fresh parameters when the handler is executed.

There are two ways to do this.

Compile Inside The Handler

The first one is to compile the state inside the handler.

const cb = () => {
  const rawHandlers = trait.properties.handlers as Static<typeof EventHandlerSchema>[];
  // Eval before sending event to assure the handler object is evaled from the latest state.
  const evaledHandler = services.stateManager.deepEval(rawHandlers[i]);

  services.apiService.send('uiMethod', {
    componentId: evaledHandler.componentId,
    name: evaledHandler.method.name,
    parameters: evaledHandler.method.parameters,
  });
};

But the problem is this would compile the state twice. One time is in the ImplWrapper when the state changed, and another time is in the handler inside. It would waste the computing resource.

Pass emit Instead Of Real Handlers

We may not have to generate the real handlers for components by event trait. We just need to find the real handlers and compile the state when some events are triggered.

Thus, we should pass a emit function instead of real handlers to the components by the ImplWrapper components.

function useEvent (props) {
  const { component, services, globalHandlerMap } = props;

  if (!globalHandlerMap.has(component.id)) {
    globalHandlerMap.set(component.id, {});
  }

  const handlerMap = useRef(globalHandlerMap.get(component.id)!);

  const send = (handler)=> {
    services.apiService.send('uiMethod', {
      componentId: handler.componentId,
      name: handler.method.name,
      parameters: handler.method.parameters,
    });
  }
  const emit = (event: string, handlers?: Handler[]) {
    if (handlers) {
      handlers.forEach(send);
    } else {
      const handlers = findHandlers(component);

      handlers.forEach(send);
    }
  }
  
  useEffect(() => {
    const handler = (s: { componentId: string; name: string; parameters?: any }) => {
      ...
      handlerMap.current[s.name](s.parameters);
    };
    services.apiService.on('uiMethod', handler);
    return () => {
      services.apiService.off('uiMethod', handler);
      globalHandlerMap.delete(c.id);
    };
  }, [services.apiService, component.id, globalHandlerMap, handlerMap]);

  
  return {
    emit,
  }
}
function ImplWrapper(props) {
  ...
  const { emit } = useEvent(props);

  return (
    ...
    <Impl emit={emit} {...}>
  )
}

This not only solves the problems mentioned above and it makes the codes easy to read.

@MrWindlike MrWindlike added feature New feature or request runtime about meta-ui runtime labels Feb 25, 2022
@Yuyz0112
Copy link
Contributor

Yuyz0112 commented Feb 28, 2022

The parameters for event handlers aren't real-time

I don't think we have parameters for the event handler at this moment, do you mean reading an out-date state in the event handler?

The codes of event implementation doesn't put together

Could you show an example of how the previous way compares to the proposed way?

@MrWindlike
Copy link
Contributor Author

I don't think we have parameters for the event handler at this moment, do you mean reading an out-date state in the event handler?

Yes.

Could you show an example of how the previous way compares to the proposed way?

The previous way is listening event in the ImplWrapper component and getting the callback functions that could send the event by the event trait. It split the related codes of events into different modules, which may not so good.

And the proposed way all codes of events are inside the useEvent hook function. And then the ImplWrapper component called useEvent can simply apply the event logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request runtime about meta-ui runtime
Projects
None yet
Development

No branches or pull requests

2 participants