Skip to content

Commit

Permalink
feat(map): 组件优化
Browse files Browse the repository at this point in the history
  • Loading branch information
wangxingkang committed Jan 15, 2024
1 parent 3e141cd commit 841fa09
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 159 deletions.
131 changes: 48 additions & 83 deletions src/hooks/useEvents.ts
Original file line number Diff line number Diff line change
@@ -1,92 +1,57 @@
import { useRef, useEffect } from 'react';
import { useDeepCompareEffect, useUnmount } from '@pansy/react-hooks';
import { isEqual } from 'lodash-es';

export interface Instance extends Record<string, any> {
on(type: string, handle: (...args: any[]) => void): void;
off(type: string, handle: (...args: any[]) => void): void;
}

export type Listeners<Events extends Record<string, string>> = {
[T in keyof Events]: (evt: any) => void;
};

export const useEvents = <Ins extends Instance, Events extends Record<string, string>>(
ins: Ins,
events: Events,
props: Record<string, any> = {},
import { useUnmount } from '@pansy/react-hooks';
import { useTrackedEffect } from './useTrackedEffect';

import type { Instance } from '../types';

export const useEvents = <Ins extends Instance, Props extends Record<string, any>>(
map: Ins,
props: Props,
options: {
eventMap: Record<string, any>;
eventList: string[];
},
) => {
const listeners = useRef<Partial<Listeners<Events>>>({});

useEffect(() => {
if (ins) {
listeners.current = listenEvents(events, props, ins);
}
}, [ins]);

useDeepCompareEffect(() => {
if (ins) {
listeners.current = updateEvents(listeners.current, props, ins);
}
}, [props]);

useUnmount(() => {
unlistenEvents(listeners.current, ins);
listeners.current = {};
});
const { eventMap = {}, eventList = [] } = options;

const listenEvents = (
partialEvents: Record<string, string> = {},
props: Record<string, any> = {},
ins: Ins,
) =>
Object.keys(partialEvents).reduce((listeners, event) => {
const eventCallback = props[event];
const eventName = partialEvents[event];

if (eventName && eventCallback) {
ins.on(eventName, eventCallback);
// @ts-ignore
listeners[event] = eventCallback;
useTrackedEffect<[Ins, ...any[]]>(
(changeIndexList = [], previousDeps, currentDeps) => {
if (!map) {
return;
}
// 需要更新的事件对应到 deps 的数组下标,但是不包含 scene 实例的更新
let eventIndexList = changeIndexList.filter((index) => !!index).map((index) => index - 1);

return listeners;
}, {});

const updateEvents = (
listeners: Partial<Listeners<Events>> = {},
currentProps: Record<string, any> = {},
ins: Ins,
) => {
const toListenOff = Object.keys(events).filter(
(eventKey) =>
(listeners[eventKey] && typeof currentProps[eventKey] !== 'function') ||
!isEqual(listeners[eventKey], currentProps[eventKey]),
);

toListenOff.forEach((key) => {
if (listeners[key]) {
ins.off(events[key], listeners[key] as any);
delete listeners[key];
// 如果本次变化为实例化则无差别遍历所有事件类型
if (changeIndexList.includes(0)) {
eventIndexList = eventList.map((_, index) => index);
}
});

const toListenOn = Object.keys(events)
.filter((key) => !listeners[key] && typeof currentProps[key] === 'function')
// @ts-ignore
.reduce((acc, next) => ((acc[next] = events[next]), acc), {});

const newListeners = listenEvents(toListenOn, currentProps, ins);

return { ...listeners, ...newListeners };
};
eventIndexList.forEach((index) => {
const eventName = eventMap[eventList[index]] as string;
const previousCallback = previousDeps?.[index + 1] as any;
const currentCallback = currentDeps?.[index + 1] as any;
// 分别注销旧的事件回调并绑定新的事件
if (previousCallback) {
map.off(eventName, previousCallback);
}
if (currentCallback) {
map.on(eventName, currentCallback);
}
});
},
[map, ...eventList.map((eventName) => props[eventName])],
);

const unlistenEvents = (listeners: Partial<Listeners<Events>> = {}, ins: Ins) => {
const toListenOff = Object.keys(events).filter((eventKey) => listeners[eventKey]);

toListenOff.forEach((key) => {
// @ts-ignore
ins.off(events[key], listeners[key]);
useUnmount(() => {
if (!map) {
return;
}
eventList.forEach((key) => {
const eventName = eventMap[key];
const callback = props[key];
if (eventName && callback) {
map.off(eventName, callback);
}
});
};
});
};
16 changes: 5 additions & 11 deletions src/hooks/useReact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import { isEqual } from 'lodash-es';
import { isFunction } from '@pansy/shared';

import { toCapitalString } from '@/utils';
import { useEvents } from './useEvents';

import type { Instance } from './useEvents';
import type { Instance } from '../types';

export interface Options<Ins, Events> {
export interface Options<Ins> {
ins?: Ins;
events: Events;
setterMap?: Record<string, Function>;
converterMap?: Record<string, Function>;
unmount?: () => void;
Expand Down Expand Up @@ -48,16 +46,12 @@ export const useReact = <
Events extends Record<string, string>,
>(
props: P = {} as P,
options: Options<Ins, Events>,
options: Options<Ins>,
) => {
const { ins, events, setterMap = {}, converterMap = {}, unmount } = options;
const { eventProps, notEventProps } = splitPropsByEvent(props);
const { ins, setterMap = {}, converterMap = {}, unmount } = options;
const { notEventProps } = splitPropsByEvent(props);
const prevProps = usePrevious(notEventProps);

console.log(eventProps);

// useEvents(ins as Ins, events, eventProps);

useDeepCompareEffect(() => {
if (ins) {
reactivePropChange(notEventProps as P, true);
Expand Down
5 changes: 4 additions & 1 deletion src/hooks/useTrackedEffect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ const diffTwoDeps = (deps1?: React.DependencyList, deps2?: React.DependencyList)
: [];
};

const useTrackedEffect = <T extends React.DependencyList>(effect: Effect<T>, deps?: [...T]) => {
export const useTrackedEffect = <T extends React.DependencyList>(
effect: Effect<T>,
deps?: [...T],
) => {
const previousDepsRef = useRef<T>();

useEffect(() => {
Expand Down
63 changes: 1 addition & 62 deletions src/map/config.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,5 @@
import type { Map } from 'mapbox-gl';
import type { MapboxOptionKeys, EventMapping } from './types';

export const mapEventMap: EventMapping = {
onError: 'error',

onLoad: 'load',
onIdle: 'idle',
onRemove: 'remove',
onRender: 'render',
onResize: 'resize',

onWebglContextLost: 'webglcontextlost',
onWebglContextRestored: 'webglcontextrestored',

onDataloading: 'dataloading',
onData: 'data',
onTileDataLoading: 'tiledataloading',
onSourceDataLoading: 'sourcedataloading',
onStyleDataLoading: 'styledataloading',
onSourceData: 'sourcedata',
onStyleData: 'styledata',

onBoxZoomCancel: 'boxzoomcancel',
onBoxZoomStart: 'boxzoomstart',
onBoxZoomEnd: 'boxzoomend',

onTouchCancel: 'touchcancel',
onTouchMove: 'touchmove',
onTouchEnd: 'touchend',
onTouchStart: 'touchstart',

onClick: 'click',
onContextMenu: 'contextmenu',
onDoubleClick: 'dblclick',
onMouseMove: 'mousemove',
onMouseUp: 'mouseup',
onMouseDown: 'mousedown',
onMouseOut: 'mouseout',
onMouseOver: 'mouseover',

onMoveStart: 'movestart',
onMove: 'move',
onMoveEnd: 'moveend',

onZoomStart: 'zoomstart',
onZoom: 'zoom',
onZoomEnd: 'zoomend',

onRotateStart: 'rotatestart',
onRotate: 'rotate',
onRotateEnd: 'rotateend',

onDragStart: 'dragstart',
onDrag: 'drag',
onDragEnd: 'dragend',

onPitchStart: 'pitchstart',
onPitch: 'pitch',
onPitchEnd: 'pitchend',

onWheel: 'wheel',
};
import type { MapboxOptionKeys } from './types';

/** 静态属性 */
export const StaticProps: MapboxOptionKeys[] = [
Expand Down
65 changes: 65 additions & 0 deletions src/map/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { EventMapping } from './types';
import type { KeysOfUnion } from '../types';

export const MapEventMap: EventMapping = {
onError: 'error',

onLoad: 'load',
onIdle: 'idle',
onRemove: 'remove',
onRender: 'render',
onResize: 'resize',

onWebglContextLost: 'webglcontextlost',
onWebglContextRestored: 'webglcontextrestored',

onDataloading: 'dataloading',
onData: 'data',
onTileDataLoading: 'tiledataloading',
onSourceDataLoading: 'sourcedataloading',
onStyleDataLoading: 'styledataloading',
onSourceData: 'sourcedata',
onStyleData: 'styledata',

onBoxZoomCancel: 'boxzoomcancel',
onBoxZoomStart: 'boxzoomstart',
onBoxZoomEnd: 'boxzoomend',

onTouchCancel: 'touchcancel',
onTouchMove: 'touchmove',
onTouchEnd: 'touchend',
onTouchStart: 'touchstart',

onClick: 'click',
onContextMenu: 'contextmenu',
onDoubleClick: 'dblclick',
onMouseMove: 'mousemove',
onMouseUp: 'mouseup',
onMouseDown: 'mousedown',
onMouseOut: 'mouseout',
onMouseOver: 'mouseover',

onMoveStart: 'movestart',
onMove: 'move',
onMoveEnd: 'moveend',

onZoomStart: 'zoomstart',
onZoom: 'zoom',
onZoomEnd: 'zoomend',

onRotateStart: 'rotatestart',
onRotate: 'rotate',
onRotateEnd: 'rotateend',

onDragStart: 'dragstart',
onDrag: 'drag',
onDragEnd: 'dragend',

onPitchStart: 'pitchstart',
onPitch: 'pitch',
onPitchEnd: 'pitchend',

onWheel: 'wheel',
};

export const MapEventList = Object.keys(MapEventMap) as KeysOfUnion<EventMapping>[];
58 changes: 58 additions & 0 deletions src/map/hooks/useMapEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useUnmount } from '@pansy/react-hooks';
import { useTrackedEffect } from '../../hooks/useTrackedEffect';

import type { Map } from 'mapbox-gl';
import type { Instance } from '../../types';

export const useMapEvent = <Ins extends Instance, Props extends Record<string, any>>(
map: Ins,
props: Props,
options: {
eventMap: Record<string, any>;
eventList: string[];
},
) => {
const { eventMap = {}, eventList = [] } = options;

useTrackedEffect<any>(
(changeIndexList = [], previousDeps: [Map, ...any[]], currentDeps: [Map, ...any[]]) => {
if (!map) {
return;
}
// 需要更新的事件对应到 deps 的数组下标,但是不包含 scene 实例的更新
let eventIndexList = changeIndexList.filter((index) => !!index).map((index) => index - 1);

// 如果本次变化为实例化则无差别遍历所有事件类型
if (changeIndexList.includes(0)) {
eventIndexList = eventList.map((_, index) => index);
}

eventIndexList.forEach((index) => {
const eventName = eventMap[eventList[index]] as string;
const previousCallback = previousDeps[index + 1] as any;
const currentCallback = currentDeps[index + 1] as any;
// 分别注销旧的事件回调并绑定新的事件
if (previousCallback) {
map.off(eventName, previousCallback);
}
if (currentCallback) {
map.on(eventName, currentCallback);
}
});
},
[map, ...eventList.map((eventName) => props[eventName])],
);

useUnmount(() => {
if (!map) {
return;
}
eventList.forEach((key) => {
const eventName = eventMap[key];
const callback = props[key];
if (eventName && callback) {
map.off(eventName, callback);
}
});
});
};
Loading

0 comments on commit 841fa09

Please sign in to comment.