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

fix: ResizeObserver should ignore shaking #18289

Merged
merged 3 commits into from Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 51 additions & 2 deletions components/_util/__tests__/util.test.js
Expand Up @@ -9,6 +9,8 @@ import triggerEvent from '../triggerEvent';
import Wave from '../wave';
import TransButton from '../transButton';
import openAnimation from '../openAnimation';
import ResizeObserver from '../resizeObserver';
import { spyElementPrototype } from '../../__tests__/util/domHook';

describe('Test utils function', () => {
beforeAll(() => {
Expand Down Expand Up @@ -143,7 +145,9 @@ describe('Test utils function', () => {
it('bindAnimationEvent should return when node is null', () => {
const wrapper = mount(
<Wave>
<button type="button" disabled>button</button>
<button type="button" disabled>
button
</button>
</Wave>,
).instance();
expect(wrapper.bindAnimationEvent()).toBe(undefined);
Expand All @@ -152,7 +156,9 @@ describe('Test utils function', () => {
it('bindAnimationEvent.onClick should return when children is hidden', () => {
const wrapper = mount(
<Wave>
<button type="button" style={{ display: 'none' }}>button</button>
<button type="button" style={{ display: 'none' }}>
button
</button>
</Wave>,
).instance();
expect(wrapper.bindAnimationEvent()).toBe(undefined);
Expand Down Expand Up @@ -220,4 +226,47 @@ describe('Test utils function', () => {
expect(done).toHaveBeenCalled();
});
});

describe('ResizeObserver', () => {
let domMock;

beforeAll(() => {
domMock = spyElementPrototype(HTMLDivElement, 'getBoundingClientRect', () => {
return {
width: 1128 + Math.random(),
height: 903 + Math.random(),
};
});
});

afterAll(() => {
domMock.mockRestore();
});

it('should not trigger `onResize` if size shaking', () => {
const onResize = jest.fn();
let divNode;

const wrapper = mount(
<ResizeObserver onResize={onResize}>
<div
ref={node => {
divNode = node;
}}
/>
</ResizeObserver>,
);

// First trigger
wrapper.instance().onResize([{ target: divNode }]);
onResize.mockReset();

// Repeat trigger should not trigger outer `onResize` with shaking
for (let i = 0; i < 10; i += 1) {
wrapper.instance().onResize([{ target: divNode }]);
}

expect(onResize).not.toHaveBeenCalled();
});
});
});
37 changes: 33 additions & 4 deletions components/_util/resizeObserver.tsx
Expand Up @@ -10,8 +10,17 @@ interface ResizeObserverProps {
onResize?: () => void;
}

class ReactResizeObserver extends React.Component<ResizeObserverProps, {}> {
interface ResizeObserverState {
height: number;
width: number;
}

class ReactResizeObserver extends React.Component<ResizeObserverProps, ResizeObserverState> {
resizeObserver: ResizeObserver | null = null;
state = {
width: 0,
height: 0,
};

componentDidMount() {
this.onComponentUpdated();
Expand All @@ -38,10 +47,30 @@ class ReactResizeObserver extends React.Component<ResizeObserverProps, {}> {
}
}

onResize = () => {
onResize: ResizeObserverCallback = (entries: ResizeObserverEntry[]) => {
const { onResize } = this.props;
if (onResize) {
onResize();

const { target } = entries[0];

const { width, height } = target.getBoundingClientRect();

/**
* Resize observer trigger when content size changed.
* In most case we just care about element size,
* let's use `boundary` instead of `contentRect` here to avoid shaking.
*/
const fixedWidth = Math.floor(width);
const fixedHeight = Math.floor(height);

if (this.state.width !== fixedWidth || this.state.height !== fixedHeight) {
this.setState({
width: fixedWidth,
height: fixedHeight,
});

if (onResize) {
onResize();
}
}
};

Expand Down