为了账号安全,请及时绑定邮箱和手机立即绑定

从流式音频功能更新 useState 时无限重新渲染

从流式音频功能更新 useState 时无限重新渲染

catspeake 2021-11-04 15:07:38
我正在构建一个应用程序 React Native,我将一组音频文件发送到 Expo AV Audio.Sound 对象中,加载它们,播放它们,然后尝试使用有关音频文件的信息更新应用程序本身的显示正在播放(特别是用户在文件中的距离)。我正在尝试通过 useState 钩子更新显示,该钩子由音频播放器的回调函数调用。我遇到的问题是,每当我尝试从音频播放器回调函数更改状态时,我都会陷入无限的重新渲染。简化代码如下:import React, { useState} from 'react';import { Audio } from 'expo-av';const AudioPlayer = ({ user }) => {    const [currentProgress, setCurrentProgress] = useState(0);    const soundObject = new Audio.Sound();    soundObject.setOnPlaybackStatusUpdate(playbackUpdate);    // sets a function that is called every 500 milliseconds as the audio is played     if(user) {          soundObject.loadAsync({user.message.path});    }    const play = () => {          soundObject.playAsync();    }    const playbackUpdate = (playbackObject) => {          setCurrentProgress(playbackObject.currentMillis);          // updating state with progress through audio file in milliseconds    }    return (          <View>             <Text>{currentProgress}</Text>             <Button title="play" onPress={play} />          </View>    )}export default AudioPlayer
查看完整描述

1 回答

?
慕哥9229398

TA贡献1877条经验 获得超6个赞

请记住,您的函数体中的所有内容都将在每次渲染上运行 - 因此在这种情况下,您正在创建一个新的soundObject并可能soundObject.loadAsync在每个渲染上运行调用。您需要利用其他钩子来避免这种情况 - 在您的情况下可能useRef和useEffect. 我建议通过 hooks api 参考熟悉这些:https : //reactjs.org/docs/hooks-reference.html


这是我如何避免不必要的影响的快速尝试。您可能想要查看和调整依赖项数组,具体取决于您希望事情如何运作以及您希望何时重新运行各种效果。例如,我不确定您是否需要Sound重新创建对象。


import React, { useState, useRef, useCallback, useEffect} from 'react';

import { Audio } from 'expo-av';

import { Button, View, Text } from 'react-native';


const AudioPlayer = ({ user }) => {

    const [currentProgress, setCurrentProgress] = useState(0);


    const soundObjectRef = useRef(new Audio.Sound());


    useEffect(() => {


      const playbackUpdate = (playbackObject) => {

          setCurrentProgress(playbackObject.currentMillis);

          // updating state with progress through audio file in milliseconds

      }

      soundObjectRef.current.setOnPlaybackStatusUpdate(playbackUpdate);

    }, []); // do this only once per component mount

    // sets a function that is called every 500 milliseconds as the audio is played 


    useEffect(() => {

      if (user) {

        soundObjectRef.current.loadAsync({user.message.path});

      }

    }, [user]); // run this anytime user changes but do not run again if user doesn't change


    const play = () => {

          soundObjectRef.current.playAsync();

    }


    return (

          <View>

             <Text>{currentProgress}</Text>

             <Button title="play" onPress={play} />

          </View>

    )


}


export default AudioPlayer


查看完整回答
反对 回复 2021-11-04
  • 1 回答
  • 0 关注
  • 135 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信