From 70d4339b4fecb42a105ee76aabf31c9b93b69b56 Mon Sep 17 00:00:00 2001 From: Johannes Reuter Date: Fri, 7 Sep 2018 11:53:03 +0200 Subject: [PATCH] dont use deprecated lifecycle methods anymore --- lib/Autocomplete.js | 82 ++++++++++++++++-------------- lib/__tests__/Autocomplete-test.js | 25 ++++----- 2 files changed, 56 insertions(+), 51 deletions(-) diff --git a/lib/Autocomplete.js b/lib/Autocomplete.js index 1658c8bb..84e957b7 100644 --- a/lib/Autocomplete.js +++ b/lib/Autocomplete.js @@ -205,11 +205,8 @@ class Autocomplete extends React.Component { this.handleKeyDown = this.handleKeyDown.bind(this) this.handleInputClick = this.handleInputClick.bind(this) this.maybeAutoCompleteText = this.maybeAutoCompleteText.bind(this) - } - - componentWillMount() { - // this.refs is frozen, so we need to assign a new object to it - this.refs = {} + // this.references is frozen, so we need to assign a new object to it + this.references = {} this._ignoreBlur = false this._ignoreFocus = false this._scrollOffset = null @@ -221,15 +218,6 @@ class Autocomplete extends React.Component { this._scrollTimer = null } - componentWillReceiveProps(nextProps) { - if (this.state.highlightedIndex !== null) { - this.setState(this.ensureHighlightedIndex) - } - if (nextProps.autoHighlight && (this.props.value !== nextProps.value || this.state.highlightedIndex === null)) { - this.setState(this.maybeAutoCompleteText) - } - } - componentDidMount() { if (this.isOpen()) { this.setMenuPositions() @@ -237,24 +225,31 @@ class Autocomplete extends React.Component { } componentDidUpdate(prevProps, prevState) { + let targetHighlightedIndex = this.state.highlightedIndex + if (this.state.highlightedIndex !== null) { + targetHighlightedIndex = this.ensureHighlightedIndex() + } + if (this.props.autoHighlight && (prevProps.value !== this.props.value || this.state.highlightedIndex === null)) { + targetHighlightedIndex = this.maybeAutoCompleteText() + } if ((this.state.isOpen && !prevState.isOpen) || ('open' in this.props && this.props.open && !prevProps.open)) this.setMenuPositions() - this.maybeScrollItemIntoView() + this.maybeScrollItemIntoView(targetHighlightedIndex) if (prevState.isOpen !== this.state.isOpen) { this.props.onMenuVisibilityChange(this.state.isOpen) } } exposeAPI(el) { - this.refs.input = el + this.references.input = el IMPERATIVE_API.forEach(ev => this[ev] = (el && el[ev] && el[ev].bind(el))) } - maybeScrollItemIntoView() { - if (this.isOpen() && this.state.highlightedIndex !== null) { - const itemNode = this.refs[`item-${this.state.highlightedIndex}`] - const menuNode = this.refs.menu + maybeScrollItemIntoView(highlightedIndex) { + if (this.isOpen() && highlightedIndex !== null) { + const itemNode = this.references[`item-${highlightedIndex}`] + const menuNode = this.references.menu scrollIntoView( findDOMNode(itemNode), findDOMNode(menuNode), @@ -334,7 +329,7 @@ class Autocomplete extends React.Component { this.setState({ isOpen: false }, () => { - this.refs.input.select() + this.references.input.select() }) } else { @@ -346,8 +341,8 @@ class Autocomplete extends React.Component { isOpen: false, highlightedIndex: null }, () => { - //this.refs.input.focus() // TODO: file issue - this.refs.input.setSelectionRange( + //this.references.input.focus() // TODO: file issue + this.references.input.setSelectionRange( value.length, value.length ) @@ -389,37 +384,46 @@ class Autocomplete extends React.Component { return items } - maybeAutoCompleteText(state, props) { - const { highlightedIndex } = state - const { value, getItemValue } = props + maybeAutoCompleteText() { + const { highlightedIndex } = this.state + const { value, getItemValue } = this.props let index = highlightedIndex === null ? 0 : highlightedIndex - let items = this.getFilteredItems(props) + let items = this.getFilteredItems(this.props) for (let i = 0; i < items.length ; i++) { - if (props.isItemSelectable(items[index])) + if (this.props.isItemSelectable(items[index])) break index = (index + 1) % items.length } - const matchedItem = items[index] && props.isItemSelectable(items[index]) ? items[index] : null + const matchedItem = items[index] && this.props.isItemSelectable(items[index]) ? items[index] : null if (value !== '' && matchedItem) { const itemValue = getItemValue(matchedItem) const itemValueDoesMatch = (itemValue.toLowerCase().indexOf( value.toLowerCase() ) === 0) if (itemValueDoesMatch) { - return { highlightedIndex: index } + this.setState({ + highlightedIndex: index + }) + return index } } - return { highlightedIndex: null } + if(this.state.highlightedIndex !== null) { + this.setState({ highlightedIndex: null }) + } + return null } - ensureHighlightedIndex(state, props) { - if (state.highlightedIndex >= this.getFilteredItems(props).length) { - return { highlightedIndex: null } + ensureHighlightedIndex() { + if (this.state.highlightedIndex >= this.getFilteredItems(this.props).length) { + this.setState({ highlightedIndex: null }) + return null + } else { + return this.state.highlightedIndex } } setMenuPositions() { - const node = this.refs.input + const node = this.references.input const rect = node.getBoundingClientRect() const computedStyle = global.window.getComputedStyle(node) const marginBottom = parseInt(computedStyle.marginBottom, 10) || 0 @@ -465,7 +469,7 @@ class Autocomplete extends React.Component { () => this.highlightItemFromMouse(index) : null, onClick: this.props.isItemSelectable(item) ? () => this.selectItemFromMouse(item) : null, - ref: e => this.refs[`item-${index}`] = e, + ref: e => this.references[`item-${index}`] = e, }) }) const style = { @@ -475,7 +479,7 @@ class Autocomplete extends React.Component { } const menu = this.props.renderMenu(items, this.props.value, style) return React.cloneElement(menu, { - ref: e => this.refs.menu = e, + ref: e => this.references.menu = e, // Ignore blur to prevent menu from de-rendering before we can process click onTouchStart: () => this.setIgnoreBlur(true), onMouseEnter: () => this.setIgnoreBlur(true), @@ -487,7 +491,7 @@ class Autocomplete extends React.Component { if (this._ignoreBlur) { this._ignoreFocus = true this._scrollOffset = getScrollOffset() - this.refs.input.focus() + this.references.input.focus() return } let setStateCallback @@ -540,7 +544,7 @@ class Autocomplete extends React.Component { } isInputFocused() { - const el = this.refs.input + const el = this.references.input return el.ownerDocument && (el === el.ownerDocument.activeElement) } diff --git a/lib/__tests__/Autocomplete-test.js b/lib/__tests__/Autocomplete-test.js index ed5b79fb..a9a27b7c 100644 --- a/lib/__tests__/Autocomplete-test.js +++ b/lib/__tests__/Autocomplete-test.js @@ -35,21 +35,21 @@ describe('Autocomplete acceptance tests', () => { it('should display autocomplete menu when input has focus', () => { expect(autocompleteWrapper.state('isOpen')).toBe(false) - expect(autocompleteWrapper.instance().refs.menu).toBe(undefined) + expect(autocompleteWrapper.instance().references.menu).toBe(undefined) // Display autocomplete menu upon input focus autocompleteInputWrapper.simulate('focus') expect(autocompleteWrapper.state('isOpen')).toBe(true) - expect(autocompleteWrapper.instance().refs.menu).not.toBe(undefined) + expect(autocompleteWrapper.instance().references.menu).not.toBe(undefined) }) it('should show results when value is a partial match', () => { // Render autocomplete results upon partial input match - expect(autocompleteWrapper.ref('menu').children().length).toBe(50) + expect(autocompleteWrapper.instance().references.menu.children.length).toBe(50) autocompleteWrapper.setProps({ value: 'Ar' }) - expect(autocompleteWrapper.ref('menu').children().length).toBe(6) + expect(autocompleteWrapper.instance().references.menu.children.length).toBe(6) }) @@ -58,7 +58,7 @@ describe('Autocomplete acceptance tests', () => { autocompleteInputWrapper.simulate('blur') expect(autocompleteWrapper.state('isOpen')).toBe(false) - expect(autocompleteWrapper.instance().refs.menu).toBe(null) + expect(autocompleteWrapper.instance().references.menu).toBe(null) }) @@ -121,6 +121,7 @@ describe('Autocomplete acceptance tests', () => { it('should reset `state.highlightedIndex` when it falls outside of possible `props.items` range', () => { const items = getStates() + autocompleteWrapper.setProps({ value: '' }) autocompleteWrapper.setState({ highlightedIndex: 10 }) items.length = 5 autocompleteWrapper.setProps({ items }) @@ -144,7 +145,7 @@ describe('Autocomplete acceptance tests', () => { tree.setProps({ value: 'ma' }) tree.setState({ highlightedIndex: 3 }) // Massachusetts tree.setProps({ value: 'mas' }) - expect(tree.instance().maybeAutoCompleteText).toHaveBeenCalledTimes(2) + expect(tree.instance().maybeAutoCompleteText).toHaveBeenCalledTimes(3) expect(tree.state('highlightedIndex')).toEqual(0) }) @@ -279,7 +280,7 @@ describe('focus management', () => { const ac = tree.instance() const input = tree.find('input') input.simulate('focus') - ac.refs.input.focus = jest.fn(() => input.simulate('focus')) + ac.references.input.focus = jest.fn(() => input.simulate('focus')) expect(tree.state('isOpen')).toBe(true) const menu = tree.find('div > div').at(0) menu.simulate('mouseEnter') @@ -288,7 +289,7 @@ describe('focus management', () => { expect(tree.state('isOpen')).toBe(true) const items = tree.find('div > div > div') items.at(3).simulate('click') - expect(ac.refs.input.focus).toHaveBeenCalledTimes(1) + expect(ac.references.input.focus).toHaveBeenCalledTimes(1) expect(tree.state('isOpen')).toBe(false) expect(ac._ignoreBlur).toBe(false) }) @@ -298,7 +299,7 @@ describe('focus management', () => { const ac = tree.instance() const input = tree.find('input') input.simulate('focus') - ac.refs.input.focus = jest.fn() + ac.references.input.focus = jest.fn() expect(tree.state('isOpen')).toBe(true) const menu = tree.find('div > div').at(0) menu.simulate('mouseEnter') @@ -307,7 +308,7 @@ describe('focus management', () => { expect(tree.state('isOpen')).toBe(true) const items = tree.find('div > div > div') items.at(3).simulate('click') - expect(ac.refs.input.focus).toHaveBeenCalledTimes(1) + expect(ac.references.input.focus).toHaveBeenCalledTimes(1) expect(ac._ignoreFocus).toBe(true) input.simulate('focus') expect(tree.state('isOpen')).toBe(false) @@ -322,7 +323,7 @@ describe('focus management', () => { const ac = tree.instance() const input = tree.find('input') input.simulate('focus') - ac.refs.input.focus = jest.fn(() => input.simulate('focus')) + ac.references.input.focus = jest.fn(() => input.simulate('focus')) expect(tree.state('isOpen')).toBe(true) const menu = tree.find('div > div').at(0) menu.simulate('mouseEnter') @@ -331,7 +332,7 @@ describe('focus management', () => { expect(tree.state('isOpen')).toBe(true) const nonItem = tree.find('span') nonItem.simulate('click') - expect(ac.refs.input.focus).toHaveBeenCalledTimes(1) + expect(ac.references.input.focus).toHaveBeenCalledTimes(1) expect(tree.state('isOpen')).toBe(true) expect(ac._ignoreBlur).toBe(true) })