Skip to content

Commit

Permalink
refactor: remove rc-util/lib/Dom/addEventListener (#42464)
Browse files Browse the repository at this point in the history
* docs: fix typo in docs

* remove rc-util/lib/Dom/addEventListener

* fix

* fix
  • Loading branch information
li-jia-nan committed May 18, 2023
1 parent dc2add0 commit 8f1d496
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 121 deletions.
28 changes: 1 addition & 27 deletions components/affix/__tests__/Affix.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { useEffect, useRef } from 'react';
import type { CSSProperties } from 'react';
import React, { useEffect, useRef } from 'react';
import type { InternalAffixClass } from '..';
import Affix from '..';
import accessibilityTest from '../../../tests/shared/accessibilityTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { render, triggerResize, waitFakeTimer } from '../../../tests/utils';
import Button from '../../button';
import { addObserveTarget, getObserverEntities } from '../utils';

const events: Partial<Record<keyof HTMLElementEventMap, (ev: Partial<Event>) => void>> = {};

Expand Down Expand Up @@ -49,8 +48,6 @@ describe('Affix Render', () => {

beforeEach(() => {
jest.useFakeTimers();
const entities = getObserverEntities();
entities.splice(0, entities.length);
});

beforeAll(() => {
Expand Down Expand Up @@ -157,23 +154,6 @@ describe('Affix Render', () => {
expect(affixInstance!.state.placeholderStyle).toBe(undefined);
});

it('instance change', async () => {
const container = document.createElement('div');
document.body.appendChild(container);
let target: HTMLDivElement | null = container;

const getTarget = () => target;
const { rerender } = render(<Affix target={getTarget}>{null}</Affix>);
await waitFakeTimer();
expect(getObserverEntities()).toHaveLength(1);
expect(getObserverEntities()[0].target).toBe(container);

target = null;
rerender(<Affix>{null}</Affix>);
expect(getObserverEntities()).toHaveLength(1);
expect(getObserverEntities()[0].target).toBe(window);
});

it('check position change before measure', async () => {
const { container } = render(
<>
Expand Down Expand Up @@ -264,11 +244,5 @@ describe('Affix Render', () => {
expect(updateCalled).toHaveBeenCalled();
});
});

it('addObserveTarget should not Throw Error when target is null', () => {
expect(() => {
addObserveTarget(null);
}).not.toThrow();
});
});
});
45 changes: 31 additions & 14 deletions components/affix/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ import classNames from 'classnames';
import ResizeObserver from 'rc-resize-observer';
import omit from 'rc-util/lib/omit';
import React, { createRef, forwardRef, useContext } from 'react';
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
import type { ConfigConsumerProps } from '../config-provider';
import { ConfigContext } from '../config-provider';
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';

import useStyle from './style';
import {
addObserveTarget,
getFixedBottom,
getFixedTop,
getTargetRect,
removeObserveTarget,
} from './utils';
import { getFixedBottom, getFixedTop, getTargetRect } from './utils';

const TRIGGER_EVENTS = [
'resize',
'scroll',
'touchstart',
'touchmove',
'touchend',
'pageshow',
'load',
] as const;

function getDefaultTarget() {
return typeof window !== 'undefined' ? window : null;
Expand Down Expand Up @@ -87,8 +90,11 @@ class InternalAffix extends React.Component<InternalAffixProps, AffixState> {
if (targetFunc) {
// [Legacy] Wait for parent component ref has its value.
// We should use target as directly element instead of function which makes element check hard.
const target = targetFunc?.() || null;
this.timer = setTimeout(() => {
addObserveTarget(targetFunc(), this);
TRIGGER_EVENTS.forEach((eventName) => {
target?.addEventListener(eventName, this.lazyUpdatePosition);
});
// Mock Event object.
this.updatePosition();
});
Expand All @@ -99,11 +105,12 @@ class InternalAffix extends React.Component<InternalAffixProps, AffixState> {
const { prevTarget } = this.state;
const targetFunc = this.getTargetFunc();
const newTarget = targetFunc?.() || null;

if (prevTarget !== newTarget) {
removeObserveTarget(this);
if (newTarget) {
addObserveTarget(newTarget, this);
TRIGGER_EVENTS.forEach((eventName) => {
prevTarget?.removeEventListener(eventName, this.lazyUpdatePosition);
newTarget?.addEventListener(eventName, this.lazyUpdatePosition);
});
// Mock Event object.
this.updatePosition();
}
Expand All @@ -126,7 +133,17 @@ class InternalAffix extends React.Component<InternalAffixProps, AffixState> {
clearTimeout(this.timer);
this.timer = null;
}
removeObserveTarget(this);
const { prevTarget } = this.state;
const targetFunc = this.getTargetFunc();
const newTarget = targetFunc?.();
TRIGGER_EVENTS.forEach((eventName) => {
newTarget?.removeEventListener(eventName, this.lazyUpdatePosition);
});
if (prevTarget !== newTarget) {
TRIGGER_EVENTS.forEach((eventName) => {
prevTarget?.removeEventListener(eventName, this.lazyUpdatePosition);
});
}
this.updatePosition.cancel();
// https://github.com/ant-design/ant-design/issues/22683
this.lazyUpdatePosition.cancel();
Expand Down
80 changes: 0 additions & 80 deletions components/affix/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import type { InternalAffixClass } from '.';

export type BindElement = HTMLElement | Window | null | undefined;

export function getTargetRect(target: BindElement): DOMRect {
Expand All @@ -27,80 +24,3 @@ export function getFixedBottom(
}
return undefined;
}

// ======================== Observer ========================
const TRIGGER_EVENTS = [
'resize',
'scroll',
'touchstart',
'touchmove',
'touchend',
'pageshow',
'load',
];

interface ObserverEntity {
target: HTMLElement | Window;
affixList: any[];
eventHandlers: { [eventName: string]: any };
}

let observerEntities: ObserverEntity[] = [];

export function getObserverEntities() {
// Only used in test env. Can be removed if refactor.
return observerEntities;
}

export function addObserveTarget<T extends InternalAffixClass>(
target: HTMLElement | Window | null,
affix?: T,
): void {
if (!target) {
return;
}

let entity = observerEntities.find((item) => item.target === target);

if (entity) {
entity.affixList.push(affix);
} else {
entity = {
target,
affixList: [affix],
eventHandlers: {},
};
observerEntities.push(entity);

// Add listener
TRIGGER_EVENTS.forEach((eventName) => {
entity!.eventHandlers[eventName] = addEventListener(target, eventName, () => {
entity!.affixList.forEach((targetAffix) => {
targetAffix.lazyUpdatePosition();
});
});
});
}
}

export function removeObserveTarget<T extends InternalAffixClass>(affix: T): void {
const observerEntity = observerEntities.find((oriObserverEntity) => {
const hasAffix = oriObserverEntity.affixList.some((item) => item === affix);
if (hasAffix) {
oriObserverEntity.affixList = oriObserverEntity.affixList.filter((item) => item !== affix);
}
return hasAffix;
});

if (observerEntity && observerEntity.affixList.length === 0) {
observerEntities = observerEntities.filter((item) => item !== observerEntity);

// Remove listener
TRIGGER_EVENTS.forEach((eventName) => {
const handler = observerEntity.eventHandlers[eventName];
if (handler && handler.remove) {
handler.remove();
}
});
}
}

0 comments on commit 8f1d496

Please sign in to comment.