Reputation: 36673
I have a search function in my ReactJS app that works fine. I've added a "clear search" function which clears the text previously entered in the search text and then requeries with an empty search text, returning to the default selection list.
The text in the search string is saved in properties so that the original search results will be displayed in the selection list when they return from editing an entry.
I would like to code the "clearSearchString" function as follows:
async clearSearchString(value) {
this.props.updateSearchString('');
this.searchFromString();
}
and so reuse the searchFromString function below, which just calls the search with whatever the searchString is in properties (which would be reset on the call to clearSearchString);
async searchFromString () {
this.setState({isLoading: true});
fetch(`/api/license/search/${this.props.searchString}`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
However, when I do it that way, the first button click does nothing, but the second button click works correctly. I thought it might have to do with the calls being asynchronous, but removing the async modifier doesn't change the result.
What does work is have them both do the search within their own methods, i.e. duplicate code:
async searchFromString() {
this.setState({isLoading: true});
fetch(`/api/license/search/${this.props.searchString}`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
async clearSearchString(value) {
this.props.updateSearchString('');
this.setState({isLoading: true});
fetch(`/api/license/search/`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
What's the problem? Why does it need two clicks to work?
Upvotes: 2
Views: 2276
Reputation: 743
Question- Why TouchableOpacity button needs to be pressed twice to hit the API or function in react native ?
Solution: import {Keyboard} from 'react-native'; then add keyboardShouldPersistTaps="handled"
<ScrollView keyboardShouldPersistTaps="handled"> <ScrollView />
Now, it will work perfectly with a single click of a button and the keyboard will also disappear.
Upvotes: 0
Reputation: 15106
State updates are not immediate (see the React setState docs), so in the code following this.props.updateSearchString('')
, the parent search-string state passed to your component as this.props.searchString
has not updated yet. The only reason the approach with the two separate functions works is that clearSearchString
there does not use this.props.searchString
, but just fetches /api/license/search/
.
You can fix this by passing a callback as the second argument to the setState
in updateSearchString
(in the parent component), which will get called after the state has been updated.
function updateSearchString(searchString, callback) {
..
this.setState(.., callback)
..
}
And write clearSearchString
as
clearSearchString(value) {
this.props.updateSearchString('', this.searchFromString);
}
Also note that referencing this.state
in a setState
argument is an anti-pattern, and should be done by passing an updater function (see the same React setState docs).
Upvotes: 2