Expo应用中使用require导入音频文件报错求助
React Native 动态加载音频文件报错解决方案
问题详情
调用自定义Hook useAudioPlayer 传入音频文件名参数时出现报错:
error: src\components\Functions.js: src\components\Functions.js:Invalid call at line 72: require("../../assets/" + audioName)
自定义Hook代码:
export const useAudioPlayer = (audioName) => { const [sound, setSound] = useState(); async function playSound() { const { sound } = await Audio.Sound.createAsync(require(`../../assets/${audioName}`)); setSound(sound); await sound.playAsync(); } useEffect(() => { return sound ? () => { sound.unloadAsync(); } : undefined; }, [sound]); return [playSound]; }
组件调用方式:
const [ playSound ] = useAudioPlayer('pop.mp3'); const HandlePress = () => { playSound() }
硬编码路径可正常运行:
const { sound } = await Audio.Sound.createAsync(require(`../../assets/pop.mp3`));
已尝试两种无效方案:
- 字符串拼接路径:
const { sound } = await Audio.Sound.createAsync(require("../../assets/" + audioName));
- 使用babel-plugin-module-resolver:
const { sound } = await Audio.Sound.createAsync(require(`@assets/${audioName}`));
问题根源
React Native 的 require 是静态编译时分析的,打包工具需要在编译阶段确定所有资源的位置,动态拼接的路径无法被正确解析,因此会抛出无效调用的错误。
可行解决方案
方案1:预定义音频资源映射表
提前将所有需要使用的音频文件通过require导入,创建一个键值对映射表,Hook内部根据传入的文件名匹配对应的资源:
// 预定义所有需要用到的音频资源 const audioAssetsMap = { 'pop.mp3': require('../../assets/pop.mp3'), 'click.mp3': require('../../assets/click.mp3'), // 按需添加其他音频文件 }; export const useAudioPlayer = (audioName) => { const [sound, setSound] = useState(); async function playSound() { // 从映射表中获取对应资源,不存在则抛出错误 const audioSource = audioAssetsMap[audioName]; if (!audioSource) { console.error(`未找到音频文件:${audioName}`); return; } const { sound } = await Audio.Sound.createAsync(audioSource); setSound(sound); await sound.playAsync(); } useEffect(() => { return sound ? () => { sound.unloadAsync(); } : undefined; }, [sound]); return [playSound]; }
方案2:直接传入已加载的资源
修改Hook的参数类型,让调用者直接传入require后的资源对象,而非文件名:
// 修改后的自定义Hook export const useAudioPlayer = (audioSource) => { const [sound, setSound] = useState(); async function playSound() { const { sound } = await Audio.Sound.createAsync(audioSource); setSound(sound); await sound.playAsync(); } useEffect(() => { return sound ? () => { sound.unloadAsync(); } : undefined; }, [sound]); return [playSound]; }
组件调用时直接传入资源:
const [ playSound ] = useAudioPlayer(require('../../assets/pop.mp3')); const HandlePress = () => { playSound() }
内容的提问来源于stack exchange,提问作者Mahmoud Hlal
相关产品推荐
相关产品推荐

