如何用useState实现删除收藏项时仅显示对应项的提示文本
问题描述
我尝试在从收藏夹中移除电影项时,仅对被移除的项显示“Removed from favorites”文本,但目前的条件渲染逻辑导致所有渲染的项都被隐藏。我意识到是使用了全局state,替换了所有项而非仅目标项。相关代码如下:
import React, { useEffect, useRef, useState } from 'react' import { View, StyleSheet, Text, Image } from 'react-native' import { FavouriteStackParams, Movie, NavigationProps } from '../types' import { FlatList } from 'react-native-gesture-handler' import { MaterialCommunityIcons } from '@expo/vector-icons' import { StorageResources } from '../api' import LoaderBox from './LoaderBox' import navigation from '../navigation' import { useFocusEffect } from '@react-navigation/native' export default function FavouriteBox() { const [favoritesFilm, setFavorite] = useState<Movie[]>([]) const [isLoadingFav, setIsLoadingFav] = useState(true) const [titleText, setTitleText] = useState(false) useFocusEffect( React.useCallback(() => { setIsLoadingFav(true) getFav() return () => { } }, [navigation]) ) async function removeMovie(id: Movie) { const value = await StorageResources.storageGet('favmovies') const alteredValue = value.filter(function (e: { id: any }) { return e.id !== id }) StorageResources.storageSave('favmovies', alteredValue) setTitleText(true) } async function getFav() { const favorites = await StorageResources.storageGet('favmovies') setFavorite(favorites) setIsLoadingFav(false) setTitleText(false) } const renderItemFav = ({ item }: any) => ( <FavMovie name={item.name} title={item.title} poster_path={item.poster_path} id={item.id} /> ) const FavMovie = ({ title, poster_path, name, id }: any) => ( <View style={styles.wrap}> {titleText && <Text style={styles.text}>Removed from favorites</Text>} {!titleText && ( <> <Image style={styles.image} source={{ uri: `https://image.tmdb.org/t/p/w500/${poster_path}`, }} /> <Text style={styles.fav}>{title}</Text> <Text style={styles.fav}>{name}</Text> <MaterialCommunityIcons onPress={() => { removeMovie(id) }} name="bookmark-minus-outline" style={styles.book} /> </> )} </View> ) }
解决方案
核心问题是全局布尔状态titleText控制了所有项的显示,要改成跟踪单个被移除电影的ID,只对目标项触发提示:
- 替换全局状态
把原来的titleText布尔状态改成存储被移除ID的数组,用来记录哪些电影刚被移除:
// 替换原有的const [titleText, setTitleText] = useState(false) const [removedMovieIds, setRemovedMovieIds] = useState<number[]>([])
- 修正移除函数
修改removeMovie,直接更新本地收藏列表(不用重新从存储读取),同时记录被移除的ID,还可以加个定时器让提示自动消失:
async function removeMovie(id: number) { // 先更新本地状态,立即反馈给用户 const updatedFavorites = favoritesFilm.filter(movie => movie.id !== id) setFavorite(updatedFavorites) // 保存到本地存储 await StorageResources.storageSave('favmovies', updatedFavorites) // 将当前移除的ID加入提示列表 setRemovedMovieIds(prev => [...prev, id]) // 可选:2秒后自动移除提示,让项消失或恢复(根据需求调整时间) setTimeout(() => { setRemovedMovieIds(prev => prev.filter(movieId => movieId !== id)) }, 2000) }
注意:这里修正了参数类型,原来的id: Movie是错误的,实际传的是数字ID,所以改成id: number。
- 修改项的渲染逻辑
让FavMovie组件只根据当前项的ID是否在removedMovieIds里来显示提示,不再依赖全局布尔值:
const FavMovie = ({ title, poster_path, name, id }: { title: string; poster_path: string; name: string; id: number }) => ( <View style={styles.wrap}> {/* 只有当前电影ID在移除列表时才显示提示 */} {removedMovieIds.includes(id) && <Text style={styles.text}>Removed from favorites</Text>} {/* 不在移除列表时显示电影内容 */} {!removedMovieIds.includes(id) && ( <> <Image style={styles.image} source={{ uri: `https://image.tmdb.org/t/p/w500/${poster_path}`, }} /> <Text style={styles.fav}>{title}</Text> <Text style={styles.fav}>{name}</Text> <MaterialCommunityIcons onPress={() => { removeMovie(id) }} name="bookmark-minus-outline" style={styles.book} /> </> )} </View> )
- 清空移除记录
在getFav函数里清空removedMovieIds,避免回到页面后旧的提示还显示:
async function getFav() { const favorites = await StorageResources.storageGet('favmovies') setFavorite(favorites) setIsLoadingFav(false) setRemovedMovieIds([]) // 清空移除记录 }
这样修改后,只有被点击移除的那项会显示提示,其他项不受影响,而且提示会自动消失(如果加了定时器),同时本地状态和存储也能正确同步。
内容的提问来源于stack exchange,提问作者greta calamari
相关产品推荐
相关产品推荐

