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: StrictMode modal scroll bar #174

Merged
merged 4 commits into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const config = {
'react/no-did-update-set-state': 0,
'react/no-find-dom-node': 0,
'import/no-extraneous-dependencies': 0,
'react/sort-comp': 0,
},
};

Expand Down
87 changes: 37 additions & 50 deletions src/PortalWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,7 @@ export interface PortalWrapperProps {
}) => React.ReactNode;
}

export interface PortalWrapperState {
_self: PortalWrapper;
}

class PortalWrapper extends React.Component<
PortalWrapperProps,
PortalWrapperState
> {
class PortalWrapper extends React.Component<PortalWrapperProps> {
container?: HTMLElement;

componentRef: React.RefObject<PortalRef> = React.createRef();
Expand All @@ -74,30 +67,54 @@ class PortalWrapper extends React.Component<
visible: boolean;
}) => void;

constructor(props: PortalWrapperProps) {
super(props);
const { visible, getContainer } = props;
if (supportDom && getParent(getContainer) === document.body) {
openCount = visible ? openCount + 1 : openCount;
}
this.state = {
_self: this,
};
}

componentDidMount() {
this.updateOpenCount();

if (!this.attachToParent()) {
this.rafId = raf(() => {
this.forceUpdate();
});
}
}

componentDidUpdate() {
componentDidUpdate(prevProps: PortalWrapperProps) {
this.updateOpenCount(prevProps);

this.setWrapperClassName();
this.attachToParent();
}

updateOpenCount = (prevProps?: Partial<PortalWrapperProps>) => {
const { visible: prevVisible, getContainer: prevGetContainer } =
prevProps || {};
const { visible, getContainer } = this.props;

// Update count
if (
visible !== prevVisible &&
supportDom &&
getParent(getContainer) === document.body
) {
if (visible && !prevVisible) {
openCount += 1;
} else if (prevProps) {
openCount -= 1;
}
}

// Clean up container if needed
const getContainerIsFunc =
typeof getContainer === 'function' &&
typeof prevGetContainer === 'function';
if (
getContainerIsFunc
? getContainer.toString() !== prevGetContainer.toString()
: getContainer !== prevGetContainer
) {
this.removeCurrentContainer();
}
};

componentWillUnmount() {
const { visible, getContainer } = this.props;
if (supportDom && getParent(getContainer) === document.body) {
Expand All @@ -108,36 +125,6 @@ class PortalWrapper extends React.Component<
raf.cancel(this.rafId);
}

static getDerivedStateFromProps(props, { prevProps, _self }) {
const { visible, getContainer } = props;
if (prevProps) {
const {
visible: prevVisible,
getContainer: prevGetContainer,
} = prevProps;
if (
visible !== prevVisible &&
supportDom &&
getParent(getContainer) === document.body
) {
openCount = visible && !prevVisible ? openCount + 1 : openCount - 1;
}
const getContainerIsFunc =
typeof getContainer === 'function' &&
typeof prevGetContainer === 'function';
if (
getContainerIsFunc
? getContainer.toString() !== prevGetContainer.toString()
: getContainer !== prevGetContainer
) {
_self.removeCurrentContainer();
}
}
return {
prevProps: props,
};
}

attachToParent = (force = false) => {
if (force || (this.container && !this.container.parentNode)) {
const parent = getParent(this.props.getContainer);
Expand Down
64 changes: 44 additions & 20 deletions tests/Portal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,30 +117,54 @@ describe('Portal', () => {
});
});

it('openCount', () => {
const Demo = ({ count, visible }: { count: number; visible: boolean }) => {
return (
<>
{new Array(count).fill(null).map((_, index) => (
<PortalWrapper key={index} visible={visible}>
{() => <div>2333</div>}
</PortalWrapper>
))}
</>
);
};
describe('openCount', () => {
it('start as 0', () => {
expect(getOpenCount()).toEqual(0);

const wrapper = mount(<Demo count={1} visible />);
expect(getOpenCount()).toEqual(1);
const wrapper = mount(
<PortalWrapper visible={false}>{() => <div>2333</div>}</PortalWrapper>,
);
expect(getOpenCount()).toEqual(0);

wrapper.setProps({ count: 2 });
expect(getOpenCount()).toEqual(2);
wrapper.setProps({ visible: true });
expect(getOpenCount()).toEqual(1);

wrapper.setProps({ count: 1 });
expect(getOpenCount()).toEqual(1);
wrapper.unmount();
});

wrapper.setProps({ visible: false });
expect(getOpenCount()).toEqual(0);
it('correct count', () => {
const Demo = ({
count,
visible,
}: {
count: number;
visible: boolean;
}) => {
return (
<>
{new Array(count).fill(null).map((_, index) => (
<PortalWrapper key={index} visible={visible}>
{() => <div>2333</div>}
</PortalWrapper>
))}
</>
);
};

expect(getOpenCount()).toEqual(0);

const wrapper = mount(<Demo count={1} visible />);
expect(getOpenCount()).toEqual(1);

wrapper.setProps({ count: 2 });
expect(getOpenCount()).toEqual(2);

wrapper.setProps({ count: 1 });
expect(getOpenCount()).toEqual(1);

wrapper.setProps({ visible: false });
expect(getOpenCount()).toEqual(0);
});
});

it('wrapperClassName', () => {
Expand Down