React Native FlatList筛选异常求助:首次加载无筛选、切换需两次点击
问题修复:观影列表切换与筛选异常
问题描述
需求:实现一个切换开关,在「待观看(To Watch)」和「已观看(Watched)」预订列表间切换。更新待观看列表中的影片后,该影片需从当前FlatList移除并出现在已观看列表,反之亦然。
当前存在的问题:
- 首次打开页面时,FlatList未应用筛选,显示所有影片
- 切换开关需点击两次才能看到列表变化
修复后的完整代码
const WatchList = () => { const uid = auth.currentUser.uid; const docRef = doc(db, 'users', uid); const [user, setUser] = useState({}); const [watched, setWatched] = useState(true); const [text, setText] = useState('To watch'); const [filteredBookings, setFilteredBookings] = useState([]); const bookingsRef = collection(db, "booking"); const [bookings, setBookings] = useState([]); useEffect(() => { getUser(); getBookings(); }, []); const getUser = async () => { const snap = await getDoc(docRef); setUser(prev => ({ ...prev, ...snap.data() })); }; const getBookings = async () => { const q = query(bookingsRef, where("users", "array-contains", auth.currentUser.uid)); const unsubscribe = onSnapshot(q, (querySnapshot) => { setBookings(querySnapshot.docs); }); return unsubscribe; }; const filterBookings = (currentBookings, isWatched) => { return currentBookings.filter(item => item.data().watched === isWatched); }; const toggleSwitch = () => { const newWatchedState = !watched; setWatched(newWatchedState); setFilteredBookings(filterBookings(bookings, newWatchedState)); setText(newWatchedState ? 'To watch' : 'Watched'); }; const updateBooking = async (id) => { try { await setDoc(doc(db, 'booking', id), { watched: true }, { merge: true }); } catch (e) { console.log(e); } }; const updateBooking1 = async (id) => { try { await setDoc(doc(db, 'booking', id), { watched: false }, { merge: true }); } catch (e) { console.log(e); } }; const deleteBooking = async (id) => { try { await deleteDoc(doc(db, 'booking', id)); } catch (e) { console.log(e); } }; useEffect(() => { if (bookings.length > 0) { setFilteredBookings(filterBookings(bookings, watched)); } }, [bookings, watched]); return ( <View> <View> <Text>{text}</Text> <Switch value={watched} onValueChange={toggleSwitch} /> </View> <FlatList data={filteredBookings} extraData={filteredBookings} keyExtractor={(item) => item.id} renderItem={({ item }) => ( <View> <View> <Text>{item.data().movie}</Text> <Text>{item.data().day} - {item.data().showtime}</Text> </View> <View> {item.data().watched === true ? ( <TouchableOpacity onPress={() => updateBooking1(item.id)}> <Image source={require('../assets/watched.png')} /> </TouchableOpacity> ) : ( <TouchableOpacity onPress={() => updateBooking(item.id)}> <Image source={require('../assets/towatch.png')} /> </TouchableOpacity> )} <TouchableOpacity onPress={() => deleteBooking(item.id)}> <Image source={require('../assets/remove.png')} /> </TouchableOpacity> </View> </View> )} /> </View> ); }; export default WatchList;
关键修复点说明
1. 初始状态与自动筛选逻辑
- 将
bookings初始化为空数组[],避免对象类型导致的筛选错误 - 新增
filterBookings工具函数统一处理筛选逻辑 - 监听
bookings和watched的变化,自动重新筛选数据,确保首次加载和数据更新后列表正确显示
2. 切换开关逻辑修正
- 先计算新的
watched状态,再基于新状态筛选数据,避免使用旧状态导致的两次点击问题 - 给
Switch添加onValueChange={toggleSwitch}绑定切换函数,确保点击开关能触发状态更新
3. 更新/删除操作的状态同步
- 修正按钮点击时调用的函数名(原代码错误调用了不存在的
updateBookings,实际应为updateBooking/updateBooking1) - 移除手动清空
filteredBookings的操作,依赖onSnapshot监听数据库变化自动更新bookings,进而触发筛选逻辑更新列表
4. FlatList优化
- 添加
keyExtractor属性,避免React Native渲染警告 - 将
extraData改为filteredBookings,确保数据更新时FlatList能正确重渲染
内容的提问来源于stack exchange,提问作者Mihailo
相关产品推荐
相关产品推荐

