React Native中使用Hook状态切换Image图片失败的问题排查
问题分析与修复方案
错误原因
- 本地图片引入方式错误:React Native中本地图片必须通过
require()加载,直接使用字符串路径无法被组件识别。你的imagens对象里仅存储了字符串路径,没有用require()包裹。 - useEffect无限循环:当前的
useEffect没有指定依赖数组,会在组件每次渲染时触发,导致setSkin反复执行,引发不必要的状态更新。 - Image组件source参数格式错误:
source需要接收require()返回的资源对象,而不是单纯的字符串,所以直接传skin或未处理的imagens[skin]都无法正常显示图片。
修复后的完整代码
import React, { useState, useEffect } from 'react'; import { SafeAreaView, TouchableOpacity, Image, Pressable, View, Text } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import BottomSheet from './BottomSheet'; import barrinhaLoja from '../assets/barrinhaLoja.png'; import vovoJuju from '../assets/vovoJuju.png'; import mcJuju from '../assets/mcJuju.png'; import patoJuju from '../assets/patoJuju.png'; import styles from './styles'; export function Home(){ // 修正:用require包裹本地图片路径 const imagens = { vovo: require('../assets/vovoJuju.png'), mc: require('../assets/mcJuju.png'), pato: require('../assets/patoJuju.png'), } const navigation = useNavigation<any>(); const [showBottomSheet, setShowBottomSheet] = useState(false); const [param, setParam] = useState(1); const [skin, setSkin] = useState('vovo') const hide = () => { setShowBottomSheet(false) } function handleAbout(){ navigation.navigate('About'); } // 修正:添加依赖数组[param],仅当param变化时执行 useEffect(() => { if(param === 1){ setSkin('vovo'); } else if(param === 2){ setSkin('mc'); } else if(param === 3){ setSkin('pato'); } }, [param]) return( <SafeAreaView style={styles.container}> <TouchableOpacity onPress={handleAbout}> <Counter /> </TouchableOpacity> <TouchableOpacity onPress={() => setShowBottomSheet(true)}> {/* 修正:传入imagens[skin],即require后的资源对象 */} <Image source={imagens[skin]} style={styles.imgvj}/> </TouchableOpacity> <BottomSheet show={showBottomSheet} height={290} onOuterClick={hide}> <Pressable onPress={hide} style={styles.bottomSheetContent}> <Image source={barrinhaLoja} style={styles.barra}/> </Pressable> <View style={styles.conteudoLoja}> <View style={styles.marginLeft48}> <TouchableOpacity onPress={() => { setParam(1); hide(); }}> <Image source={vovoJuju} style={styles.vovo}/> <Text style={styles.legendasLoja}>Vovó Juju</Text> </TouchableOpacity> </View> <View> <TouchableOpacity onPress={() => { setParam(2); hide(); }}> <Image source={mcJuju} style={styles.mc}/> <Text style={styles.legendasLoja}>MC Juju</Text> </TouchableOpacity> </View> <View> <TouchableOpacity onPress={() => { setParam(3); hide(); }}> <Image source={patoJuju} style={styles.pato}/> <Text style={styles.legendasLoja}>Pato Juju</Text> </TouchableOpacity> </View> </View> </BottomSheet> </SafeAreaView> ) }
可选优化:减少冗余状态
可以直接去掉param状态,在点击选项时直接设置skin,省去useEffect的逻辑:
// 移除param状态和对应的useEffect // 修改弹窗内的TouchableOpacity: <TouchableOpacity onPress={() => { setSkin('vovo'); hide(); }}>
这样代码更简洁,避免了中间状态的流转。
内容的提问来源于stack exchange,提问作者Lucca
相关产品推荐
相关产品推荐

