Skip to content

Commit 23cff88

Browse files
committed
update react refs to use callbacks instead of strings;
move saveRef to utils and use anywhere we want to save a ref;
1 parent f69a83f commit 23cff88

File tree

5 files changed

+51
-28
lines changed

5 files changed

+51
-28
lines changed

src/DropdownMenu.jsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
44
import toArray from 'rc-util/lib/Children/toArray';
55
import Menu from 'rc-menu';
66
import scrollIntoView from 'dom-scroll-into-view';
7-
import { getSelectKeys, preventDefaultEvent } from './util';
7+
import { getSelectKeys, preventDefaultEvent, saveRef } from './util';
88

99
export default class DropdownMenu extends React.Component {
1010
static propTypes= {
@@ -21,6 +21,11 @@ export default class DropdownMenu extends React.Component {
2121
visible: PropTypes.bool,
2222
}
2323

24+
constructor(props) {
25+
super(props);
26+
this.saveMenuRef = saveRef.bind(this, 'menuInstance');
27+
}
28+
2429
componentWillMount() {
2530
this.lastInputValue = this.props.inputValue;
2631
}
@@ -60,7 +65,7 @@ export default class DropdownMenu extends React.Component {
6065
scrollIntoViewOpts.alignWithTop = true;
6166
}
6267

63-
scrollIntoView(itemComponent, findDOMNode(this.refs.menu), scrollIntoViewOpts);
68+
scrollIntoView(itemComponent, findDOMNode(this.menuInstance), scrollIntoViewOpts);
6469
}
6570
}
6671

@@ -121,7 +126,7 @@ export default class DropdownMenu extends React.Component {
121126
}
122127

123128
return (<Menu
124-
ref="menu"
129+
ref={this.saveMenuRef}
125130
style={this.props.dropdownMenuStyle}
126131
defaultActiveFirst={defaultActiveFirstOption}
127132
{...activeKeyProps}

src/Select.jsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
UNSELECTABLE_ATTRIBUTE, UNSELECTABLE_STYLE,
1212
preventDefaultEvent, findFirstMenuItem,
1313
includesSeparators, splitBySeparators,
14-
findIndexInValueByLabel, defaultFilterFn,
14+
findIndexInValueByLabel, defaultFilterFn, saveRef,
1515
} from './util';
1616
import SelectTrigger from './SelectTrigger';
1717
import { SelectPropTypes } from './PropTypes';
@@ -21,10 +21,6 @@ import warning from 'warning';
2121
function noop() {
2222
}
2323

24-
function saveRef(name, component) {
25-
this[name] = component;
26-
}
27-
2824
function chaining(...fns) {
2925
return function (...args) { // eslint-disable-line
3026
for (let i = 0; i < fns.length; i++) {
@@ -78,6 +74,9 @@ constructor(props) {
7874
}
7975
this.saveInputRef = saveRef.bind(this, 'inputInstance');
8076
this.saveInputMirrorRef = saveRef.bind(this, 'inputMirrorInstance');
77+
this.saveRootRef = saveRef.bind(this, 'rootInstance');
78+
this.saveSelectionRef = saveRef.bind(this, 'selectionInstance');
79+
this.saveTriggerRef = saveRef.bind(this, 'triggerInstance');
8180
let open = props.open;
8281
if (open === undefined) {
8382
open = props.defaultOpen;
@@ -216,7 +215,7 @@ constructor(props) {
216215
}
217216

218217
if (state.open) {
219-
const menu = this.refs.trigger.getInnerMenu();
218+
const menu = this.triggerInstance.getInnerMenu();
220219
if (menu && menu.onKeyDown(event)) {
221220
event.preventDefault();
222221
event.stopPropagation();
@@ -362,7 +361,7 @@ constructor(props) {
362361
}
363362

364363
onChoiceAnimationLeave =() => {
365-
this.refs.trigger.refs.trigger.forcePopupAlign();
364+
this.triggerInstance.triggerInstance.forcePopupAlign();
366365
}
367366

368367
getLabelBySingleValue = (children, value) => {
@@ -505,11 +504,11 @@ constructor(props) {
505504
}
506505

507506
getPopupDOMNode=() => {
508-
return this.refs.trigger.getPopupDOMNode();
507+
return this.triggerInstance.getPopupDOMNode();
509508
}
510509

511510
getPopupMenuComponent=() => {
512-
return this.refs.trigger.getInnerMenu();
511+
return this.triggerInstance.getInnerMenu();
513512
}
514513

515514
setOpenState = (open, needFocus) => {
@@ -600,12 +599,12 @@ constructor(props) {
600599
}
601600

602601
updateFocusClassName = () => {
603-
const { refs, props } = this;
602+
const { rootInstance, props } = this;
604603
// avoid setState and its side effect
605604
if (this._focused) {
606-
classes(refs.root).add(`${props.prefixCls}-focused`);
605+
classes(rootInstance).add(`${props.prefixCls}-focused`);
607606
} else {
608-
classes(refs.root).remove(`${props.prefixCls}-focused`);
607+
classes(rootInstance).remove(`${props.prefixCls}-focused`);
609608
}
610609
}
611610

@@ -619,7 +618,7 @@ constructor(props) {
619618
this._focused = true;
620619
}
621620
} else {
622-
const selection = this.refs.selection;
621+
const selection = this.selectionInstance;
623622
if (activeElement !== selection) {
624623
selection.focus();
625624
this._focused = true;
@@ -1036,17 +1035,17 @@ constructor(props) {
10361035
getPopupContainer={props.getPopupContainer}
10371036
onMenuSelect={this.onMenuSelect}
10381037
onMenuDeselect={this.onMenuDeselect}
1039-
ref="trigger"
1038+
ref={this.saveTriggerRef}
10401039
>
10411040
<div
10421041
style={props.style}
1043-
ref="root"
1042+
ref={this.saveRootRef}
10441043
onBlur={this.onOuterBlur}
10451044
onFocus={this.onOuterFocus}
10461045
className={classnames(rootCls)}
10471046
>
10481047
<div
1049-
ref="selection"
1048+
ref={this.saveSelectionRef}
10501049
key="selection"
10511050
className={`${prefixCls}-selection
10521051
${prefixCls}-selection--${multiple ? 'multiple' : 'single'}`}

src/SelectTrigger.jsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
44
import classnames from 'classnames';
55
import DropdownMenu from './DropdownMenu';
66
import ReactDOM from 'react-dom';
7-
import { isSingleMode } from './util';
7+
import { isSingleMode, saveRef } from './util';
88

99
Trigger.displayName = 'Trigger';
1010

@@ -45,6 +45,13 @@ export default class SelectTrigger extends React.Component {
4545
children: PropTypes.any,
4646
}
4747

48+
constructor(props) {
49+
super(props);
50+
51+
this.saveMenuRef = saveRef.bind(this, 'popupMenu');
52+
this.saveTriggerRef = saveRef.bind(this, 'triggerInstance');
53+
}
54+
4855
componentDidUpdate() {
4956
const { visible, dropdownMatchSelectWidth } = this.props;
5057
if (visible) {
@@ -57,17 +64,17 @@ export default class SelectTrigger extends React.Component {
5764
}
5865

5966
getInnerMenu = () => {
60-
return this.popupMenu && this.popupMenu.refs.menu;
67+
return this.popupMenu && this.popupMenu.menuInstance;
6168
}
6269

6370
getPopupDOMNode = () => {
64-
return this.refs.trigger.getPopupDomNode();
71+
return this.triggerInstance.getPopupDomNode();
6572
}
6673

6774
getDropdownElement = (newProps) => {
6875
const props = this.props;
6976
return (<DropdownMenu
70-
ref={this.saveMenu}
77+
ref={this.saveMenuRef}
7178
{...newProps}
7279
prefixCls={this.getDropdownPrefixCls()}
7380
onMenuSelect={props.onMenuSelect}
@@ -92,10 +99,6 @@ export default class SelectTrigger extends React.Component {
9299
return `${this.props.prefixCls}-dropdown`;
93100
}
94101

95-
saveMenu = (menu) => {
96-
this.popupMenu = menu;
97-
}
98-
99102
render() {
100103
const { onPopupFocus, ...props } = this.props;
101104
const { multiple, visible, inputValue, dropdownAlign,
@@ -123,7 +126,7 @@ export default class SelectTrigger extends React.Component {
123126
return (<Trigger {...props}
124127
showAction={disabled ? [] : ['click']}
125128
hideAction={hideAction}
126-
ref="trigger"
129+
ref={this.saveTriggerRef}
127130
popupPlacement="bottomLeft"
128131
builtinPlacements={BUILT_IN_PLACEMENTS}
129132
prefixCls={dropdownPrefixCls}

src/util.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,7 @@ export function splitBySeparators(string, separators) {
141141
export function defaultFilterFn(input, child) {
142142
return String(getPropValue(child, this.props.optionFilterProp)).indexOf(input) > -1;
143143
}
144+
145+
export function saveRef(name, component) {
146+
this[name] = component;
147+
}

tests/util.spec.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
splitBySeparators,
55
getValuePropValue,
66
defaultFilterFn,
7+
saveRef,
78
} from '../src/util';
89

910
describe('includesSeparators', () => {
@@ -94,3 +95,14 @@ describe('defaultFilterFn', () => {
9495
expect(defaultFilterFn.call(testerInstance, 'wrong-val', child)).toBe(false);
9596
});
9697
});
98+
99+
describe('saveRef', () => {
100+
const mock = {};
101+
const saveTestRef = saveRef.bind(mock, 'testInstance');
102+
103+
it('adds a property with the given name to context', () => {
104+
expect(mock.testInstance).toBe(undefined);
105+
saveTestRef('bar');
106+
expect(mock.testInstance).toBe('bar');
107+
});
108+
});

0 commit comments

Comments
 (0)