Skip to content

Commit c90e41b

Browse files
authoredDec 2, 2019
perf(getItemProps): memoize the event handlers for item (#841)
* memoize the event handlers for item * use getItemId instead * use fastMemoize instead of lodash
1 parent c2fd95a commit c90e41b

File tree

3 files changed

+85
-72
lines changed

3 files changed

+85
-72
lines changed
 

‎.size-snapshot.json

+30-30
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,59 @@
11
{
22
"dist/downshift.cjs.js": {
3-
"bundled": 82171,
4-
"minified": 38051,
5-
"gzipped": 9612
3+
"bundled": 82391,
4+
"minified": 38211,
5+
"gzipped": 9665
66
},
77
"preact/dist/downshift.cjs.js": {
8-
"bundled": 80880,
9-
"minified": 37003,
10-
"gzipped": 9510
8+
"bundled": 81100,
9+
"minified": 37163,
10+
"gzipped": 9564
1111
},
1212
"preact/dist/downshift.umd.min.js": {
13-
"bundled": 93946,
14-
"minified": 32080,
15-
"gzipped": 9869
13+
"bundled": 96750,
14+
"minified": 33202,
15+
"gzipped": 10210
1616
},
1717
"preact/dist/downshift.umd.js": {
18-
"bundled": 108010,
19-
"minified": 38136,
20-
"gzipped": 11406
18+
"bundled": 110814,
19+
"minified": 39259,
20+
"gzipped": 11755
2121
},
2222
"dist/downshift.umd.min.js": {
23-
"bundled": 98585,
24-
"minified": 33398,
25-
"gzipped": 10431
23+
"bundled": 101389,
24+
"minified": 34520,
25+
"gzipped": 10797
2626
},
2727
"dist/downshift.umd.js": {
28-
"bundled": 137170,
29-
"minified": 47034,
30-
"gzipped": 14022
28+
"bundled": 139974,
29+
"minified": 48161,
30+
"gzipped": 14354
3131
},
3232
"dist/downshift.esm.js": {
33-
"bundled": 81790,
34-
"minified": 37742,
35-
"gzipped": 9551,
33+
"bundled": 81990,
34+
"minified": 37887,
35+
"gzipped": 9604,
3636
"treeshaked": {
3737
"rollup": {
38-
"code": 629,
39-
"import_statements": 303
38+
"code": 650,
39+
"import_statements": 324
4040
},
4141
"webpack": {
42-
"code": 27616
42+
"code": 27794
4343
}
4444
}
4545
},
4646
"preact/dist/downshift.esm.js": {
47-
"bundled": 80480,
48-
"minified": 36675,
49-
"gzipped": 9449,
47+
"bundled": 80680,
48+
"minified": 36820,
49+
"gzipped": 9503,
5050
"treeshaked": {
5151
"rollup": {
52-
"code": 630,
53-
"import_statements": 304
52+
"code": 651,
53+
"import_statements": 325
5454
},
5555
"webpack": {
56-
"code": 27659
56+
"code": 27837
5757
}
5858
}
5959
}

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"dependencies": {
6868
"@babel/runtime": "^7.4.5",
6969
"compute-scroll-into-view": "^1.0.9",
70+
"fast-memoize": "^2.5.1",
7071
"prop-types": "^15.7.2",
7172
"react-is": "^16.9.0"
7273
},

‎src/downshift.js

+54-42
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import PropTypes from 'prop-types'
44
import {Component, cloneElement} from 'react'
55
import {isForwardRef} from 'react-is'
6+
import memoize from 'fast-memoize'
67
import {isPreact, isReactNative} from './is.macro'
78
import setA11yStatus from './set-a11y-status'
89
import * as stateChangeTypes from './stateChangeTypes'
@@ -833,10 +834,8 @@ class Downshift extends Component {
833834
!!this.props.environment.document.activeElement &&
834835
!!this.props.environment.document.activeElement.dataset &&
835836
this.props.environment.document.activeElement.dataset.toggle &&
836-
(this._rootNode &&
837-
this._rootNode.contains(
838-
this.props.environment.document.activeElement,
839-
))
837+
this._rootNode &&
838+
this._rootNode.contains(this.props.environment.document.activeElement)
840839
if (!this.isMouseDown && !downshiftButtonIsActive) {
841840
this.reset({type: stateChangeTypes.blurInput})
842841
}
@@ -869,6 +868,49 @@ class Downshift extends Component {
869868
}
870869
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ MENU
871870

871+
getItemPropsEventHandlers = memoize(
872+
(index, item, onClick, onPress, onMouseMove, onMouseDown) => {
873+
const onSelectKey = isReactNative
874+
? /* istanbul ignore next (react-native) */ 'onPress'
875+
: 'onClick'
876+
const customClickHandler = isReactNative
877+
? /* istanbul ignore next (react-native) */ onPress
878+
: onClick
879+
880+
return {
881+
// onMouseMove is used over onMouseEnter here. onMouseMove
882+
// is only triggered on actual mouse movement while onMouseEnter
883+
// can fire on DOM changes, interrupting keyboard navigation
884+
onMouseMove: callAllEventHandlers(onMouseMove, () => {
885+
if (index === this.getState().highlightedIndex) {
886+
return
887+
}
888+
this.setHighlightedIndex(index, {
889+
type: stateChangeTypes.itemMouseEnter,
890+
})
891+
892+
// We never want to manually scroll when changing state based
893+
// on `onMouseMove` because we will be moving the element out
894+
// from under the user which is currently scrolling/moving the
895+
// cursor
896+
this.avoidScrolling = true
897+
this.internalSetTimeout(() => (this.avoidScrolling = false), 250)
898+
}),
899+
onMouseDown: callAllEventHandlers(onMouseDown, event => {
900+
// This prevents the activeElement from being changed
901+
// to the item so it can remain with the current activeElement
902+
// which is a more common use case.
903+
event.preventDefault()
904+
}),
905+
[onSelectKey]: callAllEventHandlers(customClickHandler, () => {
906+
this.selectItemAtIndex(index, {
907+
type: stateChangeTypes.clickItem,
908+
})
909+
}),
910+
}
911+
},
912+
)
913+
872914
/////////////////////////////// ITEM
873915
getItemProps = ({
874916
onMouseMove,
@@ -888,44 +930,14 @@ class Downshift extends Component {
888930
this.items[index] = item
889931
}
890932

891-
const onSelectKey = isReactNative
892-
? /* istanbul ignore next (react-native) */ 'onPress'
893-
: 'onClick'
894-
const customClickHandler = isReactNative
895-
? /* istanbul ignore next (react-native) */ onPress
896-
: onClick
897-
898-
const enabledEventHandlers = {
899-
// onMouseMove is used over onMouseEnter here. onMouseMove
900-
// is only triggered on actual mouse movement while onMouseEnter
901-
// can fire on DOM changes, interrupting keyboard navigation
902-
onMouseMove: callAllEventHandlers(onMouseMove, () => {
903-
if (index === this.getState().highlightedIndex) {
904-
return
905-
}
906-
this.setHighlightedIndex(index, {
907-
type: stateChangeTypes.itemMouseEnter,
908-
})
909-
910-
// We never want to manually scroll when changing state based
911-
// on `onMouseMove` because we will be moving the element out
912-
// from under the user which is currently scrolling/moving the
913-
// cursor
914-
this.avoidScrolling = true
915-
this.internalSetTimeout(() => (this.avoidScrolling = false), 250)
916-
}),
917-
onMouseDown: callAllEventHandlers(onMouseDown, event => {
918-
// This prevents the activeElement from being changed
919-
// to the item so it can remain with the current activeElement
920-
// which is a more common use case.
921-
event.preventDefault()
922-
}),
923-
[onSelectKey]: callAllEventHandlers(customClickHandler, () => {
924-
this.selectItemAtIndex(index, {
925-
type: stateChangeTypes.clickItem,
926-
})
927-
}),
928-
}
933+
const enabledEventHandlers = this.getItemPropsEventHandlers(
934+
index,
935+
item,
936+
onClick,
937+
onMouseDown,
938+
onMouseMove,
939+
onPress,
940+
)
929941

930942
// Passing down the onMouseDown handler to prevent redirect
931943
// of the activeElement if clicking on disabled items

0 commit comments

Comments
 (0)
Please sign in to comment.