Skip to content

Commit 0404790

Browse files
chalettujeff-phillips-18
authored andcommitted
fix(All): Remove bindMethods in favor of Class properties (#313)
1 parent b32aeb8 commit 0404790

28 files changed

Lines changed: 402 additions & 692 deletions

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ when possible and accept [props](https://facebook.github.io/react/docs/component
135135
* If you need a constant file, it should be called `{Component_Name}Constants.js` (Component_Name with PascalCase)
136136
* Each component should treat as a standalone package and live under its own folder
137137
* Single file per component with **default export**
138+
* Avoid using the bindMethods syntax for attaching methods to a class. Instead use class properties for example ```testMethod = () => { return 'test'} ```
138139
* When component is a set of components (e.g., ListGroup and ListGroupItem),
139140
they should live in the same folder named on the parent component (e.g., ListGroup)
140141
* Each component folder should have an `index.js` file with **named exports** of all the relevant components in the folder

src/common/controlled.js

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3-
import { nullValues, bindMethods, selectKeys, filterKeys } from './helpers';
3+
import { nullValues, selectKeys, filterKeys } from './helpers';
44

55
/*
66
controlled(stateTypes, defaults)(WrappedComponent)
@@ -35,16 +35,7 @@ import { nullValues, bindMethods, selectKeys, filterKeys } from './helpers';
3535
*/
3636
const controlled = ({ types, defaults = {}, persist }) => WrappedComponent => {
3737
class ControlledComponent extends React.Component {
38-
constructor() {
39-
super();
40-
this.state = { ...nullValues(types), ...defaults };
41-
bindMethods(this, [
42-
'sessionKey',
43-
'savePersistent',
44-
'loadPersistent',
45-
'setControlledState'
46-
]);
47-
}
38+
state = { ...nullValues(types), ...defaults };
4839

4940
componentDidMount() {
5041
this.loadPersistent();
@@ -60,21 +51,21 @@ const controlled = ({ types, defaults = {}, persist }) => WrappedComponent => {
6051
window.removeEventListener('beforeunload', this.savePersistent);
6152
}
6253

63-
setControlledState(updater) {
54+
setControlledState = updater => {
6455
this.setState(updater);
65-
}
56+
};
6657

67-
loadPersistent() {
58+
loadPersistent = () => {
6859
if (persist && persist.length > 0) {
6960
const fromPersisted =
7061
window &&
7162
window.sessionStorage &&
7263
window.sessionStorage.getItem(this.sessionKey());
7364
fromPersisted && this.setState(JSON.parse(fromPersisted));
7465
}
75-
}
66+
};
7667

77-
savePersistent() {
68+
savePersistent = () => {
7869
if (persist && persist.length > 0) {
7970
const toPersist = selectKeys(this.state, persist);
8071
window &&
@@ -84,11 +75,9 @@ const controlled = ({ types, defaults = {}, persist }) => WrappedComponent => {
8475
JSON.stringify(toPersist)
8576
);
8677
}
87-
}
78+
};
8879

89-
sessionKey() {
90-
return this.props.sessionKey || JSON.stringify(persist);
91-
}
80+
sessionKey = () => this.props.sessionKey || JSON.stringify(persist);
9281

9382
render() {
9483
const controlledStateProps = filterKeys(

src/common/helpers.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import React from 'react';
22

33
/** Equivalent to calling `this.someMethod = this.someMethod.bind(this)` for every method name in the methods array. */
44
export const bindMethods = (context, methods) => {
5+
// eslint-disable-next-line no-console
6+
console.warn(`
7+
bindMethods usage is deprecated in favor of class methods.
8+
bindMethods will be removed in the next major release
9+
`);
510
methods.forEach(method => {
611
context[method] = context[method].bind(context);
712
});

src/components/Filter/__mocks__/mockFilterExample.js

Lines changed: 31 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from 'react';
22
import { Filter, FormControl, Toolbar } from '../../../index';
3-
import { bindMethods } from '../../../common/helpers';
43

54
export const mockFilterExampleFields = [
65
{
@@ -72,28 +71,13 @@ export const mockFilterExampleFields = [
7271
];
7372

7473
export class MockFilterExample extends React.Component {
75-
constructor() {
76-
super();
77-
78-
bindMethods(this, [
79-
'updateCurrentValue',
80-
'onValueKeyPress',
81-
'selectFilterType',
82-
'filterValueSelected',
83-
'filterCategorySelected',
84-
'categoryValueSelected',
85-
'removeFilter',
86-
'clearFilters'
87-
]);
88-
89-
this.state = {
90-
currentFilterType: mockFilterExampleFields[0],
91-
activeFilters: [],
92-
currentValue: ''
93-
};
94-
}
74+
state = {
75+
currentFilterType: mockFilterExampleFields[0],
76+
activeFilters: [],
77+
currentValue: ''
78+
};
9579

96-
onValueKeyPress(keyEvent) {
80+
onValueKeyPress = keyEvent => {
9781
const { currentValue, currentFilterType } = this.state;
9882

9983
if (keyEvent.key === 'Enter' && currentValue && currentValue.length > 0) {
@@ -102,9 +86,9 @@ export class MockFilterExample extends React.Component {
10286
keyEvent.stopPropagation();
10387
keyEvent.preventDefault();
10488
}
105-
}
89+
};
10690

107-
categoryValueSelected(value) {
91+
categoryValueSelected = value => {
10892
const { currentValue, currentFilterType, filterCategory } = this.state;
10993

11094
if (filterCategory && currentValue !== value) {
@@ -117,11 +101,11 @@ export class MockFilterExample extends React.Component {
117101
this.filterAdded(currentFilterType, filterValue);
118102
}
119103
}
120-
}
104+
};
121105

122-
clearFilters() {
106+
clearFilters = () => {
123107
this.setState({ activeFilters: [] });
124-
}
108+
};
125109

126110
filterAdded = (field, value) => {
127111
let filterText = '';
@@ -145,14 +129,14 @@ export class MockFilterExample extends React.Component {
145129
this.setState({ activeFilters });
146130
};
147131

148-
filterCategorySelected(category) {
132+
filterCategorySelected = category => {
149133
const { filterCategory } = this.state;
150134
if (filterCategory !== category) {
151135
this.setState({ filterCategory: category, currentValue: '' });
152136
}
153-
}
137+
};
154138

155-
filterValueSelected(filterValue) {
139+
filterValueSelected = filterValue => {
156140
const { currentFilterType, currentValue } = this.state;
157141

158142
if (filterValue !== currentValue) {
@@ -161,9 +145,9 @@ export class MockFilterExample extends React.Component {
161145
this.filterAdded(currentFilterType, filterValue);
162146
}
163147
}
164-
}
148+
};
165149

166-
removeFilter(filter) {
150+
removeFilter = filter => {
167151
const { activeFilters } = this.state;
168152

169153
const index = activeFilters.indexOf(filter);
@@ -174,9 +158,9 @@ export class MockFilterExample extends React.Component {
174158
];
175159
this.setState({ activeFilters: updated });
176160
}
177-
}
161+
};
178162

179-
selectFilterType(filterType) {
163+
selectFilterType = filterType => {
180164
const { currentFilterType } = this.state;
181165
if (currentFilterType !== filterType) {
182166
this.setState(prevState => ({
@@ -192,11 +176,11 @@ export class MockFilterExample extends React.Component {
192176
: prevState.categoryValue
193177
}));
194178
}
195-
}
179+
};
196180

197-
updateCurrentValue(event) {
181+
updateCurrentValue = event => {
198182
this.setState({ currentValue: event.target.value });
199-
}
183+
};
200184

201185
renderInput() {
202186
const { currentFilterType, currentValue, filterCategory } = this.state;
@@ -290,7 +274,6 @@ export class MockFilterExample extends React.Component {
290274
export const mockFilterExampleSource = `
291275
import React from 'react';
292276
import { Filter, FormControl, Toolbar } from '../../../index';
293-
import { bindMethods } from '../../../common/helpers';
294277
295278
export const mockFilterExampleFields = [
296279
{
@@ -362,26 +345,12 @@ export const mockFilterExampleFields = [
362345
];
363346
364347
export class MockFilterExample extends React.Component {
365-
constructor() {
366-
super();
367-
368-
bindMethods(this, [
369-
'updateCurrentValue',
370-
'onValueKeyPress',
371-
'selectFilterType',
372-
'filterValueSelected',
373-
'filterCategorySelected',
374-
'categoryValueSelected',
375-
'removeFilter',
376-
'clearFilters'
377-
]);
378-
379-
this.state = {
348+
349+
state = {
380350
currentFilterType: mockFilterExampleFields[0],
381351
activeFilters: [],
382352
currentValue: ''
383353
};
384-
}
385354
386355
filterAdded = (field, value) => {
387356
let filterText = '';
@@ -407,7 +376,7 @@ export class MockFilterExample extends React.Component {
407376
this.setState({ activeFilters: activeFilters });
408377
};
409378
410-
selectFilterType(filterType) {
379+
selectFilterType = filterType => {
411380
const { currentFilterType } = this.state;
412381
if (currentFilterType !== filterType) {
413382
this.setState(prevState => {
@@ -427,7 +396,7 @@ export class MockFilterExample extends React.Component {
427396
}
428397
}
429398
430-
filterValueSelected(filterValue) {
399+
filterValueSelected = filterValue => {
431400
const { currentFilterType, currentValue } = this.state;
432401
433402
if (filterValue !== currentValue) {
@@ -438,14 +407,14 @@ export class MockFilterExample extends React.Component {
438407
}
439408
}
440409
441-
filterCategorySelected(category) {
410+
filterCategorySelected = category => {
442411
const { filterCategory } = this.state;
443412
if (filterCategory !== category) {
444413
this.setState({ filterCategory: category, currentValue: '' });
445414
}
446415
}
447416
448-
categoryValueSelected(value) {
417+
categoryValueSelected = value => {
449418
const { currentValue, currentFilterType, filterCategory } = this.state;
450419
451420
if (filterCategory && currentValue !== value) {
@@ -460,11 +429,11 @@ export class MockFilterExample extends React.Component {
460429
}
461430
}
462431
463-
updateCurrentValue(event) {
432+
updateCurrentValue = event => {
464433
this.setState({ currentValue: event.target.value });
465434
}
466435
467-
onValueKeyPress(keyEvent) {
436+
onValueKeyPress = keyEvent => {
468437
const { currentValue, currentFilterType } = this.state;
469438
470439
if (keyEvent.key === 'Enter' && currentValue && currentValue.length > 0) {
@@ -475,7 +444,7 @@ export class MockFilterExample extends React.Component {
475444
}
476445
}
477446
478-
removeFilter(filter) {
447+
removeFilter = filter => {
479448
const { activeFilters } = this.state;
480449
481450
let index = activeFilters.indexOf(filter);
@@ -488,7 +457,7 @@ export class MockFilterExample extends React.Component {
488457
}
489458
}
490459
491-
clearFilters() {
460+
clearFilters = () => {
492461
this.setState({ activeFilters: [] });
493462
}
494463

src/components/InfoTip/InfoTip.js

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,27 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33
import { Dropdown } from '../Dropdown';
4-
import { bindMethods, KEY_CODES } from '../../common/helpers';
4+
import { KEY_CODES } from '../../common/helpers';
55

66
class InfoTip extends React.Component {
7-
constructor(props) {
8-
super(props);
9-
bindMethods(this, [
10-
'handleKeyDown',
11-
'handleClick',
12-
'handleBackFocus',
13-
'handleBlur'
14-
]);
15-
this.state = { open: false, footerFocused: false };
16-
}
7+
state = { open: false, footerFocused: false };
178

18-
handleEnterKeyDown(event) {
9+
handleEnterKeyDown = event => {
1910
this.setState({ open: !this.state.open });
2011
event.preventDefault();
21-
}
12+
};
2213

23-
handleTabKeyDown(event) {
14+
handleTabKeyDown = event => {
2415
if (this.state.footerFocused) {
2516
this.setState({ open: false, footerFocused: false });
2617
} else {
2718
this.setState({ footerFocused: true });
2819
}
2920
event.stopPropagation();
3021
event.nativeEvent.stopImmediatePropagation();
31-
}
22+
};
3223

33-
handleKeyDown(event) {
24+
handleKeyDown = event => {
3425
if (event.shiftKey && event.keyCode) {
3526
return this.handleBackFocus();
3627
}
@@ -44,24 +35,24 @@ class InfoTip extends React.Component {
4435
default:
4536
return null;
4637
}
47-
}
38+
};
4839

49-
handleBackFocus() {
40+
handleBackFocus = () => {
5041
if (this.state.open) {
5142
this.setState({ open: false });
5243
}
53-
}
44+
};
5445

55-
handleClick(event) {
46+
handleClick = event => {
5647
event.preventDefault();
5748
this.setState({ open: !this.state.open });
58-
}
59-
handleBlur(event) {
49+
};
50+
handleBlur = event => {
6051
if (event && event.relatedTarget) {
6152
event.relatedTarget.click();
6253
}
6354
this.setState({ open: false });
64-
}
55+
};
6556

6657
render() {
6758
const { children, onToggle, ...props } = this.props;

0 commit comments

Comments
 (0)