diff --git a/benchmark.js b/benchmark.js new file mode 100644 index 00000000..13a78c2f --- /dev/null +++ b/benchmark.js @@ -0,0 +1,44 @@ +var jsdom = require("jsdom"); +global.document = jsdom.jsdom(''); +global.window = document.defaultView; +global.navigator = window.navigator; + + +var Benchmark = require('benchmark'); +var React = require('react'); +var TestUtils = require("react/addons").addons.TestUtils; +global.assert = require('chai').assert; + +// A super simple DOM ready for React to render into + +var ReactTypeahead = require('./lib/react-typeahead').Typeahead; +var TypeaheadOption = require("./lib/typeahead/option"); + +global.simulateTextInput = function(component, value) { + var node = component.refs.entry; + node.value = value; + TestUtils.Simulate.change(node); + return TestUtils.scryRenderedComponentsWithType(component, TypeaheadOption); +}; + +var props = { + options: [ + "a", + "ab", + "dfe", + ], +}; +global.component = TestUtils.renderIntoDocument(React.createElement(ReactTypeahead, props)); + +console.log("running benchmark"); + +var suite = new Benchmark.Suite(); +suite.add("Filtering options", function() { + var results = simulateTextInput(component, "a"); + assert.equal(results.length, 2); + simulateTextInput(component, ""); +}).on('complete', function() { + console.log(this["0"].stats.mean); +}).run({async: false}); + +console.log("done"); diff --git a/package.json b/package.json index 499cd2c3..bdb1af51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-typeahead", - "version": "1.1.5", + "version": "1.1.6", "description": "React-based typeahead and typeahead-tokenizer", "keywords": [ "react", @@ -40,12 +40,14 @@ }, "main": "lib/react-typeahead.js", "devDependencies": { + "benchmark": "^1.0.0", "browserify": "^8.0.2", "chai": "^1.9.1", "es5-shim": "^4.0.1", "gulp": "^3.8.7", "gulp-mocha-phantomjs": "^0.8.1", "gulp-react": "^3.0.1", + "jsdom": "^7.2.1", "literalify": "^0.4.0", "lodash": "^2.4.1", "mocha": "^1.21.4", @@ -61,7 +63,8 @@ "build": "browserify ./src/react-typeahead.js -t reactify -t literalify -x react -s ReactTypeahead -o ./dist/react-typeahead.js", "watchify": "watchify ./src/react-typeahead.js -t reactify -t literalify -x react -s ReactTypeahead -o ./dist/react-typeahead.js", "lib": "gulp build", - "prepublish": "npm run lib" + "prepublish": "npm run lib", + "benchmark": "node ./benchmark.js" }, "literalify": { "react": "window.React || require('react')" diff --git a/src/typeahead/index.js b/src/typeahead/index.js index c13d2dd0..beed3d1d 100644 --- a/src/typeahead/index.js +++ b/src/typeahead/index.js @@ -81,9 +81,6 @@ var Typeahead = React.createClass({ getInitialState: function() { return { - // The currently visible set of options - visible: this.getOptionsForValue(this.props.defaultValue, this.props.options), - // This should be called something else, "entryValue" entryValue: this.props.value || this.props.defaultValue, @@ -105,6 +102,10 @@ var Typeahead = React.createClass({ return result; }, + getVisibleOptions: function() { + return this.getOptionsForValue(this.state.entryValue, this.props.options); + }, + setEntryText: function(value) { this.refs.entry.value = value; this._onTextEntryUpdated(); @@ -117,7 +118,7 @@ var Typeahead = React.createClass({ _hasCustomValue: function() { if (this.props.allowCustomValues > 0 && this.state.entryValue.length >= this.props.allowCustomValues && - this.state.visible.indexOf(this.state.entryValue) < 0) { + this.getVisibleOptions().indexOf(this.state.entryValue) < 0) { return true; } return false; @@ -143,7 +144,7 @@ var Typeahead = React.createClass({ return ( 0 ? this.state.visible[0] : null); + selection : (this.getVisibleOptions().length > 0 ? this.getVisibleOptions()[0] : null); if (option === null && this._hasCustomValue()) { option = this._getCustomValue(); @@ -234,7 +233,7 @@ var Typeahead = React.createClass({ return; } var newIndex = this.state.selectionIndex === null ? (delta == 1 ? 0 : delta) : this.state.selectionIndex + delta; - var length = this.state.visible.length; + var length = this.getVisibleOptions().length; if (this._hasCustomValue()) { length += 1; } @@ -283,12 +282,6 @@ var Typeahead = React.createClass({ event.preventDefault(); }, - componentWillReceiveProps: function(nextProps) { - this.setState({ - visible: this.getOptionsForValue(this.state.entryValue, nextProps.options) - }); - }, - render: function() { var inputClasses = {}; inputClasses[this.props.customClasses.input] = !!this.props.customClasses.input; @@ -368,7 +361,7 @@ var Typeahead = React.createClass({ }, _hasHint: function() { - return this.state.visible.length > 0 || this._hasCustomValue(); + return this.getVisibleOptions().length > 0 || this._hasCustomValue(); } }); diff --git a/test/typeahead-test.js b/test/typeahead-test.js index 83fb658f..6a050d9e 100644 --- a/test/typeahead-test.js +++ b/test/typeahead-test.js @@ -564,4 +564,50 @@ describe('Typeahead Component', function() { }); }) }); + + context("issue-128", function(){ + var WrappingComponent = React.createClass({ + getInitialState: function(){ + return { + value: "", + options: [ + {value: "a"}, + {value: "ab"}, + {value: "abc"}, + {value: "other"} + ] + }; + }, + onChange: function(event) { + var newState = { + value: event.target.value, + options: this.state.options + }; + this.setState(newState); + }, + render: function() { + return (); + } + }); + + beforeEach(function() { + this.wrappingComponent = TestUtils.renderIntoDocument( + + ); + this.component = TestUtils.findRenderedComponentWithType( + this.wrappingComponent, + Typeahead + ); + }); + + it("should not autocomplete one step behind the input", function() { + var results = simulateTextInput(this.component, "a"); + assert.equal(results.length, 3); + }); + }); });