Skip to content

Commit

Permalink
Wrap componentWillReceiveProps in setTimeout
Browse files Browse the repository at this point in the history
We're seeing an issue where the props that we pass also change
when the value in the input-field does. This causes two problems

1)
selectedItems gets overwritten again even though we've not changed
the default selected account. This can be avoided by comparing the
prop to see if it's actually changed. The react docs for
componentWillReceiveProps also state that it may be called even
if the props haven't changed and that checking for changes is a
good idea in the first place.

2)
Since the component is reading the inputValue from state, there's
a chance it will get the previous value if setState was called
from onInputChange in the same cycle of the event loop because
setState is asynchronous. This is solved by wrapping the code
in setTimeout, forcing it to run after we're sure the state has
been settled. There might be a Better Way to do this but I'm not
really up to the task right now.
  • Loading branch information
ivarni committed Dec 9, 2016
1 parent a7d265b commit a716b72
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

# v3.0.4
* Fix an esoteric bug that could cause the dropdown to display the wrong state if the value of the input was changed while the component was receiving a props-change

# v3.0.3
* Fix svg caret that was jumping up and down due to it's (slightly bigger) container being rotated instead of the actual icon itself

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nfe-account-selector-react",
"version": "3.0.3",
"version": "3.0.4",
"main": "lib/account-selector.js",
"scripts": {
"build": "babel -d lib/. --ignore=*.test.js src/.",
Expand Down Expand Up @@ -75,6 +75,7 @@
"classnames": "^2.2.5",
"ffe-checkbox-react": "^2.2.1",
"ffe-icons-react": "0.4.2",
"lodash.isequal": "^4.4.0",
"nfe-amount-formatter": "^2.0.1",
"nfe-if": "^2.0.1",
"react-scrollbar": "0.4.1"
Expand Down
26 changes: 21 additions & 5 deletions src/selectors/base-selector.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, {PropTypes, Component} from 'react';
import classNames from 'classnames';
import isEqual from 'lodash.isequal';
import ChevronIkon from 'ffe-icons-react/chevron-ikon';
import i18n from '../i18n/i18n';
import KryssIkon from 'ffe-icons-react/kryss-ikon';
Expand Down Expand Up @@ -53,11 +54,26 @@ class BaseSelector extends Component {
}

componentWillReceiveProps(props) {
const {inputValue} = this.state;
this.setState({
filteredItems: this.filterItems(props.items, inputValue),
selectedItems: props.selectedItems
});
// If we happen to change props as a result of the input-value change callback
// then this function will be called right after onInputChange but the inputValue
// in the state will not have been updated yet. Wrapping the code in setTimeout
// ensures that setState will have updated the state before we use it to filter
// the selection.
window.setTimeout(() => {
const {inputValue} = this.state;

const nextState = {
filteredItems: this.filterItems(props.items, inputValue),
};

// Only update the selectedItems state if the props have actually changed
// to prevent accidentally reverting to the default selection.
if (!isEqual(props.selectedItems, this.props.selectedItems)) {
nextState.selectedItems = props.selectedItems;
}

this.setState(nextState);
},0);
}

onReset(evt) {
Expand Down

0 comments on commit a716b72

Please sign in to comment.