- Atualmente a
meutudo
possui vários mecanismos de disparo de evento e caso futuramente for implementado ou removido algum, nós podemos pensar em alguma maneira para separar esses disparos; - Pensando nisso, podemos implementar um
gerenciador de eventos
para ele ter controle dos eventos disparados e dolistener
ter a lógica do disparo de evento;
- Gerenciador;
Singleton
, para nunca ser recriado;- Ele possui 3 características principais:
- Eventos
- Disparo
- Listeners
export class EventManager {
private static INSTANCE: EventManager;
private events: EventManagerObject;
private constructor() {
this.events = new Map();
}
public static getInstance() {
if (!this.INSTANCE) {
this.INSTANCE = new EventManager();
}
return this.INSTANCE;
}
public on(event: string, callback: EventManagerCallback): CallableFunction {
const listeners = this.events.get(event);
if (listeners) {
listeners.add(callback);
} else {
this.events.set(event, new Set([callback]));
}
return () => {
this.events.get(event)?.delete(callback);
};
}
public emmit(event: string, params?: Partial<EventManagerCallbackParams>) {
const listeners = this.events.get(event);
if (listeners) {
for (const callback of listeners.values()) {
callback(params);
}
}
}
}
- Onde vão estar os eventos, vamos pensar nesse
Map
como se fosse um objeto;
- Método responsável por cadastrar os listeners dos eventos, então nela existe 2 parâmetros:
- Nome do evento, sempre sendo utilizado como
enum
; - Funções que recebem os dados que foram enviados, seguindo uma tipagem.
Tipagem
enum EventType {
INTERACTION = 'interaction',
}
interface EventManagerCallbackParams {
eventValues?: Record<string, string>;
eventName?: string;
eventType?: EventType;
eventScreenId?: string;
}
export type EventManagerCallback = (
params?: Partial<EventManagerCallbackParams>,
) => void;
Exemplo de implementação:
enum Event {
TEST = 'evento_teste'
}
function listener(params) {
// Onde vou enviar os eventos para as plataformas
}
// Criar um LISTENER
manager.on(Event.TEST, callback)
- Método responsável para disparar os eventos e com os listeners cadastrados vão receber esses eventos;
- Esse método possúi 2 parâmetros:
- Nome do evento, sempre sendo utilizado como
enum
; - Os dados que devem ser enviados.
Exemplo de implementação
const params = {
eventName: 'evento_de_teste',
eventType: EventType.INTERACTION,
eventScreenId: 'tela_de_inicio',
};
manager.emmit(Event.TEST. params)
- Podemos adicionar esse manager através de
hook
ou até mesmo deHOC
; - Como o manager não depende de nenhuma alteração de estado ou algo parecido então o
hook
não é necessário, foi apenas escrito para facilicar o método;
Exemplo de implementação
import React, { FunctionComponent } from 'react';
import { useEventManager } from '~/events/manager/hooks/useEventManager';
export function withEventManager<Type extends object>() {
return (Component: FunctionComponent<Type>) => {
return (props: Type) => {
const { manager } = useEventManager();
return <Component {...props} eventManager={manager} />;
};
};
}
Exemplo de implementação
import { EventManager } from '~/events/manager/event-manager';
export function useEventManager() {
const manager = EventManager.getInstance();
return { manager };
}
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { useEventManager } from '~/events/manager/hooks/useEventManager';
import { ComponentWithEventManager } from '~/events/manager/types';
import { withEventManager } from '~/events/manager/hoc/withEventManager';
import { EventFGTS } from '~/events/manager/enums/fgts';
interface ComponentProps {}
type Props = ComponentWithEventManager<ComponentProps>;
function ExamplePage(props: Props) {
const { manager } = useEventManager();
function onButtonPress() {
const eventName = 'fgts:start_integration';
const eventScreenId = 'fgts_tela_de_integracao';
const params = {
eventName,
eventScreenId,
};
manager.emmit(EventFGTS.START_INTEGRATION, params);
props?.eventManager?.emmit(EventFGTS.START_INTEGRATION, params);
}
return (
<View>
<TouchableOpacity onPress={onButtonPress}>
<Text>Iniciar integração</Text>
</TouchableOpacity>
</View>
);
}
export default withEventManager<Props>()(ExamplePage);
import { EventManager } from '~/events/manager/event-manager';
export enum EventType {
INTERACTION = 'interaction',
}
export interface EventManagerCallbackParams {
eventValues?: Record<string, string>;
eventName?: string;
eventType?: EventType;
eventScreenId?: string;
}
export type EventManagerCallback = (
params?: Partial<EventManagerCallbackParams>,
) => void;
export type EventManagerObject = Map<string, Set<EventManagerCallback>>;
export type ComponentWithEventManager<Props = {}> = Props & {
eventManager?: EventManager;
};
- Como na aplicação pode conter vários listeners e de vários contextos, podemos separa-los e criar um arquivo principal apenas para dar o
start
em todos:
Exemplo:
import { EventManager } from '~/events/manager/event-manager';
import { EventFGTS } from '~/events/manager/enums/fgts';
export function fgtsListener(manager: EventManager) {
manager.on(EventFGTS.START_INTEGRATION, params => {
// caso seja necessário apenas um emmit [sem parâmetros]
if (params) {
const { eventName, eventScreenId, eventType } = params;
}
});
}
//[index.ts]
import { EventManager } from '~/events/manager/event-manager';
import { fgtsListener } from '~/events/manager/listeners/fgts';
export function startAllListeners(manager: EventManager) {
const listeners = [fgtsListener];
for (const listener of listeners) {
console.log(`[Event-Manager]: Start listener -> ${listener.name} with success!`);
listener(manager);
}
}
-src
----events
-------manager
----------types.ts
----------event-manager.ts
----------listeners
-------------index
-------------[nome-produto].ts
----------------index
-----------enums
--------------[nome-produto].ts
-----------hoc
--------------withEventManager
-----------hook
--------------useEventManager.ts
- Podemos pensar em implementar um tipo de
repositório
para apenas cadastrar e ele ter a inteligência de separar e disparar para cada: Exemplo:
function insiderRepository(params) {
// disparar para a Insider
}
const eventManager = EventManager.getInstance([insiderRepository])
eventManager.on({{ event_name }}, ({ repositories, params }) => {
for(const repository for repositories) {
repository(params)
}
})
- Isso facilitaria no cadastro de novas plataformas e remoção de outras.