从流音频功能更新useState时无限重渲染 [英] Infinite re-renders when updating useState from streaming audio function

查看:122
本文介绍了从流音频功能更新useState时无限重渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个应用程序React Native,其中我将一系列音频文件发送到Expo AV Audio.Sound对象,加载它们,然后播放它们,然后尝试使用有关以下信息的信息来更新应用程序本身的显示播放的音频文件(特别是用户在文件中播放的距离).我正在尝试通过useState钩子更新显示,该钩子由音频播放器的回调函数调用.

I'm building an app React Native where I'm sending an array of audio files into an Expo AV Audio.Sound object, loading them, playing them, and then attempting to update the display of the app itself with info about the audio file being played (specifically how far through the file the user is). I'm trying to update the display through the useState hook which is being called by a callback function from the audio player.

我遇到的问题是,每当我尝试更改音频播放器回调函数的状态时,都会陷入无限的重新渲染中.简化的代码如下:

The problem I'm running into is that anytime I try to change the state from the audio player callback function I get thrown into an infinite re-render. Simplified code is below:

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

推荐答案

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

Remember that everything in your function body will run on every render - so in this case you are creating a new soundObject and potentially running the soundObject.loadAsync call on every single render. You'll need to take advantage of other hooks to avoid this - in your case likely useRef and useEffect. I would recommend getting familiar with these through the hooks api reference: https://reactjs.org/docs/hooks-reference.html

在这里,我将如何避免不必要的影响.您可能需要检查和调整依赖项数组,具体取决于您希望事情如何运行以及何时希望重新运行各种效果.我不确定是否需要重新创建Sound对象.

Here's a quick stab at how I would avoid the unnecessary effects. You'll probably want to review and tweak the dependency arrays depending on how you want things to function and when you want the various effects to be re-run. I'm not sure if you ever need the Sound object to be re-created for example.

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

这篇关于从流音频功能更新useState时无限重渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆