Skip to content

Convert class components that don't have to be class components to function components to reduce bundle size #3794

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

Merged
merged 1 commit into from
Oct 3, 2019
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/brown-terms-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-select': patch
---

Convert class components that don't have to be class components to function components to reduce bundle size
141 changes: 70 additions & 71 deletions packages/react-select/src/components/MultiValue.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
/** @jsx jsx */
import { Component, type Node } from 'react';
import { type Node } from 'react';
import { jsx, ClassNames } from '@emotion/core';
import { CrossIcon } from './indicators';
import type { CommonProps } from '../types';
Expand Down Expand Up @@ -85,91 +85,90 @@ export type MultiValueRemoveProps = {
},
selectProps: any,
};
export class MultiValueRemove extends Component<MultiValueRemoveProps> {
render() {
const { children, innerProps } = this.props;
return <div {...innerProps}>{children || <CrossIcon size={14} />}</div>;
}
export function MultiValueRemove({
children,
innerProps,
}: MultiValueRemoveProps) {
return <div {...innerProps}>{children || <CrossIcon size={14} />}</div>;
}

class MultiValue extends Component<MultiValueProps> {
static defaultProps = {
cropWithEllipsis: true,
};
render() {
const {
children,
className,
components,
cx,
data,
getStyles,
innerProps,
isDisabled,
removeProps,
selectProps,
} = this.props;
const MultiValue = (props: MultiValueProps) => {
const {
children,
className,
components,
cx,
data,
getStyles,
innerProps,
isDisabled,
removeProps,
selectProps,
} = props;

const { Container, Label, Remove } = components;
const { Container, Label, Remove } = components;

return (
<ClassNames>
{({ css, cx: emotionCx }) => (
<Container
return (
<ClassNames>
{({ css, cx: emotionCx }) => (
<Container
data={data}
innerProps={{
...innerProps,
className: emotionCx(
css(getStyles('multiValue', props)),
cx(
{
'multi-value': true,
'multi-value--is-disabled': isDisabled,
},
className
)
),
}}
selectProps={selectProps}
>
<Label
data={data}
innerProps={{
...innerProps,
className: emotionCx(
css(getStyles('multiValue', this.props)),
css(getStyles('multiValueLabel', props)),
cx(
{
'multi-value': true,
'multi-value--is-disabled': isDisabled,
'multi-value__label': true,
},
className
)
),
}}
selectProps={selectProps}
>
<Label
data={data}
innerProps={{
className: emotionCx(
css(getStyles('multiValueLabel', this.props)),
cx(
{
'multi-value__label': true,
},
className
)
),
}}
selectProps={selectProps}
>
{children}
</Label>
<Remove
data={data}
innerProps={{
className: emotionCx(
css(getStyles('multiValueRemove', this.props)),
cx(
{
'multi-value__remove': true,
},
className
)
),
...removeProps,
}}
selectProps={selectProps}
/>
</Container>
)}
</ClassNames>
);
}
}
{children}
</Label>
<Remove
data={data}
innerProps={{
className: emotionCx(
css(getStyles('multiValueRemove', props)),
cx(
{
'multi-value__remove': true,
},
className
)
),
...removeProps,
}}
selectProps={selectProps}
/>
</Container>
)}
</ClassNames>
);
};

MultiValue.defaultProps = {
cropWithEllipsis: true,
};

export default MultiValue;
47 changes: 19 additions & 28 deletions packages/react-select/src/components/containers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
/** @jsx jsx */
import { Component, type Node } from 'react';
import { type Node } from 'react';
import { jsx } from '@emotion/core';
import type { CommonProps, KeyboardEventHandler } from '../types';

Expand Down Expand Up @@ -79,34 +79,25 @@ export const valueContainerCSS = ({
position: 'relative',
overflow: 'hidden',
});
export class ValueContainer extends Component<ValueContainerProps> {
render() {
const {
children,
className,
cx,
isMulti,
getStyles,
hasValue,
} = this.props;
export const ValueContainer = (props: ValueContainerProps) => {
const { children, className, cx, isMulti, getStyles, hasValue } = props;

return (
<div
css={getStyles('valueContainer', this.props)}
className={cx(
{
'value-container': true,
'value-container--is-multi': isMulti,
'value-container--has-value': hasValue,
},
className
)}
>
{children}
</div>
);
}
}
return (
<div
css={getStyles('valueContainer', props)}
className={cx(
{
'value-container': true,
'value-container--is-multi': isMulti,
'value-container--has-value': hasValue,
},
className
)}
>
{children}
</div>
);
};

// ==============================
// Indicator Container
Expand Down
64 changes: 35 additions & 29 deletions packages/react-select/src/internal/DummyInput.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
// @flow
/** @jsx jsx */
import { Component } from 'react';
import { jsx } from '@emotion/core';

export default class DummyInput extends Component<any> {
render () {
const { in: inProp, out, onExited, appear, enter, exit, innerRef, emotion, ...props } = this.props;
return(
<input
ref={innerRef}
{...props}
css={{
label: 'dummyInput',
// get rid of any default styles
background: 0,
border: 0,
fontSize: 'inherit',
outline: 0,
padding: 0,
// important! without `width` browsers won't allow focus
width: 1,
export default function DummyInput({
in: inProp,
out,
onExited,
appear,
enter,
exit,
innerRef,
emotion,
...props
}: any) {
return (
<input
ref={innerRef}
{...props}
css={{
label: 'dummyInput',
// get rid of any default styles
background: 0,
border: 0,
fontSize: 'inherit',
outline: 0,
padding: 0,
// important! without `width` browsers won't allow focus
width: 1,

// remove cursor on desktop
color: 'transparent',
// remove cursor on desktop
color: 'transparent',

// remove cursor on mobile whilst maintaining "scroll into view" behaviour
left: -100,
opacity: 0,
position: 'relative',
transform: 'scale(0)',
}}
/>
);
}
// remove cursor on mobile whilst maintaining "scroll into view" behaviour
left: -100,
opacity: 0,
position: 'relative',
transform: 'scale(0)',
}}
/>
);
}
12 changes: 5 additions & 7 deletions packages/react-select/src/internal/ScrollCaptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class ScrollCaptor extends Component<CaptorProps> {
}
}
stopListening(el: HTMLElement) {

// all the if statements are to appease Flow 😢
if (typeof el.removeEventListener === 'function') {
el.removeEventListener('wheel', this.onWheel, false);
Expand Down Expand Up @@ -134,10 +133,9 @@ type SwitchProps = CaptorProps & {
isEnabled: boolean,
};

export default class ScrollCaptorSwitch extends Component<SwitchProps> {
static defaultProps = { isEnabled: true };
render() {
const { isEnabled, ...props } = this.props;
return isEnabled ? <ScrollCaptor {...props} /> : this.props.children;
}
export default function ScrollCaptorSwitch({
isEnabled = true,
...props
}: SwitchProps) {
return isEnabled ? <ScrollCaptor {...props} /> : props.children;
}