Reputation: 2692
I want the view to always be updated with the result of the latest call to searchWiki()
. I've used a module that resolves repeated calls to $.ajax
to the value returned by the most recent call.
It still seems to go out of sync and show the result of previous calls however. I'm guessing this is because setState
is async? How should I keep the two async operations in sync?
In addition, I realize I should put in a debounce somewhere, but I'm not sure what I should debounce. handleChange
, searchWiki
or latestAjax
?
Here is a demo: http://codepen.io/prashcr/pen/obXvWv
Try typing stuff then backspacing to see what I mean.
Search component
<div style={style}>
<input
value={this.props.search}
// this calls searchWiki with e.target.value
onInput={this.handleChange}
/>
</div>
searchWiki function of parent component
searchWiki (search) {
console.log('searchWiki called with: ' + search);
if (!search) {
this.setState({results: []});
}
else {
// "latest" taken from https://github.com/bjoerge/promise-latest
let latestAjax = latest($.ajax);
let options = {
url: this.props.url + search,
dataType: 'jsonp'
};
latestAjax(options)
.then(data => {
var results = data.query.search.map(res => {
res.url = 'http://en.wikipedia.org/wiki/' + encodeURIComponent(res.title);
return res;
});
this.setState({results: results});
})
.error(e => console.log(e.message));
}
}
Upvotes: 0
Views: 944
Reputation: 30009
The handleChange
function is too generic to be debounced with a hardcoded value as you might want to use this search component elsewhere. However, you still want to catch the repeating action as early as possible and ensure that it never does any unnecessary work.
Therefore I would suggest that you debounce the handleChange
function with an optional prop, defaulting to 0ms.
getDefaultProps() {
return {
debounce: 0
};
},
render() {
// ...
return (
<div style={style}>
<input
// ...
onInput={debounce(this.handleChange, this.props.debounce)}/>
</div>
);
}
Then make sure you pass this prop whenever you want to debounce the handler.
<Search onSearch={this.searchWiki} debounce={1000} />
Your other problem is happening because you are calling latest
inside your searchWiki
function and you only call the returned function once! Each time you call searchWiki
you create a new latestAjax
function.
For it to work, you'll need to call the returned function multiple times.
This means defining the wrapped $.ajax
function outside of searchWiki
function.
latestAjax: latest($.ajax),
searchWiki(search) {
// ...
this.latestAjax(options)
.then(data => {
});
}
Upvotes: 1