如何用handleFavoritePress切换CardFeirasPopulares的Image图片源?
图片源切换与收藏状态切换实现方案
一、通用方法:通过函数切换<Image />组件的图片源
要实现图片源切换,核心是利用React的状态管理(useState)——直接修改变量不会触发组件重渲染,只有状态更新才会让组件重新渲染,从而更新Image的source属性。
实现步骤:
- 导入
useState钩子 - 定义状态变量保存当前图片源
- 编写切换函数,在函数中通过
setState更新状态 - 将Image的
source绑定到状态变量
示例代码:
import { useState } from 'react'; import { Image, TouchableOpacity } from 'react-native'; const ExampleComponent = () => { // 初始化状态为默认图片 const [imageSource, setImageSource] = useState(icons.favorite); const toggleImage = () => { // 切换状态:当前是未收藏图标则切换为已收藏,反之亦然 setImageSource(prev => prev === icons.favorite ? icons.favoritechecked : icons.favorite); }; return ( <TouchableOpacity onPress={toggleImage}> <Image source={imageSource} style={{ width: 24, height: 24 }} /> </TouchableOpacity> ); };
二、针对你的React Native项目:实现收藏状态独立切换
你的代码存在两个核心问题:未用useState管理状态(直接赋值不会触发重渲染)、所有列表项共用同一状态(点击一个会同步所有卡片)。以下是修改后的完整代码:
1. 修改FeirasPopulares组件
为每个列表项单独管理收藏状态,用数组存储每个item的收藏状态:
import { useState } from 'react'; import {View, FlatList, Text, TouchableOpacity, StyleSheet} from 'react-native' import CardFeirasPopulares from '../../common/cards/popular/CardFeirasPopulares' import { useRouter } from "expo-router"; import { icons } from '../../../constants'; const FeirasPopulares = () => { // 初始化收藏状态数组,所有item默认未收藏(false) const [favoriteStates, setFavoriteStates] = useState(Array(6).fill(false)); const router = useRouter(); // 补上卡片点击逻辑(可根据需求修改) const handleCardPress = () => { // router.push('/feira-detail'); }; // 接收item索引,单独切换对应项的收藏状态 const handleFavoritePress = (index) => { setFavoriteStates(prevStates => { const newStates = [...prevStates]; newStates[index] = !newStates[index]; return newStates; }); }; return( <View style={styles.container}> <View style={styles.header}> <Text style={styles.headerTitle} numberOfLines={1}>Feiras Recomendadas</Text> <TouchableOpacity> <Text style={styles.showAll}>Mostrar Todos</Text> </TouchableOpacity> </View> <View> <FlatList data={[1,2,3,4,5,6]} renderItem={({item, index}) => ( <CardFeirasPopulares nome={"Rua Tal"} dias={['Seg', 'Qua']} handleCardPress={handleCardPress} handleFavoritePress={() => handleFavoritePress(index)} url={favoriteStates[index] ? icons.favoritechecked : icons.favorite} /> )} horizontal keyExtractor={(item) => item.toString()} contentContainerStyle={{columnGap: 16}} showsHorizontalScrollIndicator = {false} /> </View> </View> ) } const styles = StyleSheet.create({ container: { padding: 16, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, }, headerTitle: { fontSize: 18, fontWeight: 'bold', }, showAll: { fontSize: 14, color: '#007AFF', }, }); export default FeirasPopulares;
2. CardFeirasPopulares组件(仅做简化调整)
import { View, Text, TouchableOpacity, Image, StyleSheet} from "react-native"; import { icons } from "../../../../constants"; const CardFeirasPopulares = ({nome, dias, handleCardPress, handleFavoritePress, url}) => { return( <TouchableOpacity style={styles.container} onPress={handleCardPress} > <View > <Text style={styles.cardTitle}>{nome}</Text> <Text style={styles.cardSubtitle}>{dias[0]} - {dias[1]}</Text> </View> <TouchableOpacity onPress={handleFavoritePress} style={{padding: 8}}> <Image source={url} resizeMode="cover" style={styles.icon} /> </TouchableOpacity> </TouchableOpacity> ) } const styles = StyleSheet.create({ container: { width: 180, padding: 12, backgroundColor: '#fff', borderRadius: 8, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, cardTitle: { fontSize: 16, fontWeight: '500', }, cardSubtitle: { fontSize: 12, color: '#666', marginTop: 4, }, icon: { width: 24, height: 24, }, }); export default CardFeirasPopulares;
关键修改说明:
- 用
useState创建favoriteStates数组,单独存储每个列表项的收藏状态 handleFavoritePress接收item索引,仅修改对应位置的状态,实现单个卡片独立切换- FlatList的
renderItem中传递索引,根据favoriteStates[index]动态传递图片url - 补全未定义的
handleCardPress函数,避免报错 - 优化
keyExtractor将item转为字符串,消除React警告
内容的提问来源于stack exchange,提问作者torzin
相关产品推荐
相关产品推荐

