I have been searching for a while on Google but couldn’t find a clear answer, my problem is that I have a search screen with a text input and a select input and button, so I click the button after entering the input text and results show after an api is called. But the issue is when I navigate to a different screen and back to the search screen the results stays. I need it to be empty the input text field and the result.
I tried many many "solutions" but none worked. I used a useEffect() hook and it did not work, tried to set the records array to empty but did not work
here is my search screen code:
import {
StyleSheet,
View,
ActivityIndicator,
FlatList,
Button,
} from 'react-native';
import React, { useState, useEffect } from 'react';
import AppTextInput from '../components/AppTextInput';
import Card from '../components/Card';
import colors from '../config/colors';
import axios from 'axios';
import { baseApiUrl, apikey } from '../api/config/apiLinks';
import AppPicker from '../components/AppPicker';
import AppText from '../components/AppText';
import { openBrowserAsync } from 'expo-web-browser';
const options = [
{ value: 'news', label: 'News' },
{ value: 'videos', label: 'Videos' },
{ value: 'documentaries', label: 'Documentaries' },
{ value: 'channels', label: 'Channels' },
];
export default function SearchScreen({ navigation }) {
const [selected, setSelected] = useState(options[0]);
const [input, setInput] = useState();
const [resultRecords, setResultRecords] = useState([]);
const [totalPages, setTotalPages] = useState();
const [currentPage, setCurrentPage] = useState(1);
const [errorMessage, setErrorMessage] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [attachEnd, setAttachEnd] = useState(false);
const url =
baseApiUrl +
'/search/search-get.php?' +
apikey +
'&category=' +
selected.value +
'&q=' +
input +
'&page=' +
currentPage +
'&count=15';
const loadSearchResult = () => {
setIsLoading(true);
console.log('selected: ', selected.value);
console.log('url: ', url);
axios
.get(url)
.then((response) => {
setErrorMessage(0);
console.log(response);
setTotalPages(response.data.totalPages);
if (attachEnd) {
setResultRecords([...resultRecords, ...response.data.data]);
} else {
setResultRecords(response.data.data);
}
setIsLoading(false);
setAttachEnd(false);
console.log('records: ', resultRecords);
})
.catch((error) => {
if (error.response.status == 404) {
setErrorMessage('Results not found!');
}
setIsLoading(false);
console.log(error.response);
});
};
const onInputChange = (text) => {
if (text != '') {
setInput(text);
console.log('onInputChange: ', input);
}
};
const renderLoader = () => {
return isLoading ? (
<View style={styles.loaderStyle}>
<ActivityIndicator size="large" color="#aaa" />
</View>
) : null;
};
//this useEffect execute the function only once
useEffect(() => {
setResultRecords([]);
setInput('');
}, [navigation]);
return (
<View style={styles.container}>
<View style={styles.innerContainer}>
<AppTextInput
placeholder="Search..."
icon="magnify"
onFieldChange={onInputChange}
/>
</View>
<View style={styles.innerContainer}>
<AppPicker
selectedItem={selected}
onSelectItem={(item) => setSelected(item)}
items={options}
icon="apps"
placeholder="Category"
/>
</View>
<View style={styles.button}>
<Button title="Search" onPress={loadSearchResult} />
</View>
<View style={styles.results}>
{errorMessage == '' && (
<FlatList
data={resultRecords}
keyExtractor={(records) => records.title}
renderItem={({ item }) => (
<Card
title={item.title}
feedName={item.feedName}
date={item.pubDate}
imageUrl={item.image}
onPress={() => {
console.log('selectedOnPress: ', selected);
console.log('browser: ', item.link);
if (selected.value == 'news') {
navigation.navigate(
'NewsDetailsScreen',
item
);
} else if (selected.value == 'videos') {
navigation.navigate(
'YoutubeVideoDetailsScreen',
item
);
} else if (
selected.value == 'documentaries'
) {
openBrowserAsync(item.link);
} else if (selected.value == 'channels') {
openBrowserAsync(item.link);
}
}}
/>
)}
ListFooterComponent={renderLoader}
/>
)}
{errorMessage != '' && (
<AppText style={styles.results}>{errorMessage}</AppText>
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
loaderStyle: {
marginVertical: 16,
alignItems: 'center',
},
container: {
padding: 15,
paddingBottom: 50,
// backgroundColor: colors.light,
flexDirection: 'column',
width: '100%',
},
innerContainer: {
width: '100%',
},
button: {
width: '100%',
marginTop: 15,
marginBottom: 15,
},
results: {
marginTop: 15,
paddingBottom: 50,
textAlign: 'center',
},
});
3
Answers
You need to use
useFocusEffect
insteaduseEffect
:I recommend read the documentation https://reactnavigation.org/docs/navigation-lifecycle/
You should use
replace
instead ofnavigate
.Note:
navigate
: Will push the new route into the stack. The previous route won’t be unmountedreplace
: Will replace the previous route with the new route.You can also do it using
Promise.prototype.finally
like this: