React Native搜索页面返回后清空输入与结果的问题求助
解决方案
你的问题出在两个核心点:
- 依赖
navigation对象的useEffect仅在组件挂载时执行一次,无法在从其他页面返回当前页面时触发清空逻辑 - 输入框未与
input状态绑定,导致即使重置状态,输入框内容也不会同步更新
具体修改步骤:
1. 导入必要的钩子
添加useFocusEffect和useCallback的导入:
import React, { useState, useCallback } from 'react'; import { useFocusEffect } from '@react-navigation/native';
2. 替换原useEffect为useFocusEffect
useFocusEffect会在屏幕获得焦点时触发,完美匹配返回页面时清空内容的需求:
useFocusEffect( useCallback(() => { // 清空搜索输入、结果、错误信息 setInput(''); setResultRecords([]); setErrorMessage(''); // 可选:重置选择器到默认选项、页码 setSelected(options[0]); setCurrentPage(1); }, []) );
3. 给输入框绑定状态值
修改AppTextInput组件,添加value属性实现UI与状态同步:
<AppTextInput placeholder="Search..." icon="magnify" onFieldChange={onInputChange} value={input || ''} />
4. 修复输入框状态更新逻辑
原onInputChange仅在输入非空时更新状态,导致清空输入框时状态不同步,修改为:
const onInputChange = (text) => { setInput(text); console.log('onInputChange: ', text); };
修改后的完整代码(关键修改已标注)
import { StyleSheet, View, ActivityIndicator, FlatList, Button, } from 'react-native'; import React, { useState, useCallback } from 'react'; import { useFocusEffect } from '@react-navigation/native'; // 新增导入 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) { // 添加可选链避免undefined报错 setErrorMessage('Results not found!'); } setIsLoading(false); console.log(error.response); }); }; const onInputChange = (text) => { setInput(text); // 移除非空判断,确保所有输入变化同步到状态 console.log('onInputChange: ', text); }; const renderLoader = () => { return isLoading ? ( <View style={styles.loaderStyle}> <ActivityIndicator size="large" color="#aaa" /> </View> ) : null; }; // 替换原useEffect为useFocusEffect useFocusEffect( useCallback(() => { setInput(''); setResultRecords([]); setErrorMessage(''); setSelected(options[0]); setCurrentPage(1); }, []) ); return ( <View style={styles.container}> <View style={styles.innerContainer}> <AppTextInput placeholder="Search..." icon="magnify" onFieldChange={onInputChange} value={input || ''} // 新增value绑定 /> </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', }, });
额外说明
useFocusEffect是React Navigation专为屏幕焦点变化场景设计的钩子,比依赖navigation对象的useEffect更可靠- 输入框绑定
value是受控组件的标准实现,确保UI始终与状态保持一致 - 修复了
setErrorMessage(0)的逻辑错误,统一用空字符串表示无错误状态 - 添加
error.response?.status可选链,避免请求失败时因response为undefined导致的报错
内容的提问来源于stack exchange,提问作者f1ian
相关产品推荐
相关产品推荐

