Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/422.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 从流媒体音频功能更新useState时无限重渲染_Javascript_Reactjs_React Native_Audio_React Hooks - Fatal编程技术网

Javascript 从流媒体音频功能更新useState时无限重渲染

Javascript 从流媒体音频功能更新useState时无限重渲染,javascript,reactjs,react-native,audio,react-hooks,Javascript,Reactjs,React Native,Audio,React Hooks,我正在构建一个应用程序React Native,将一系列音频文件发送到Expo AV audio.Sound对象中,加载并播放它们,然后尝试使用正在播放的音频文件的信息更新应用程序本身的显示,特别是用户通过文件的距离。我试图通过useState钩子更新显示,该钩子由音频播放器的回调函数调用 我遇到的问题是,每当我试图更改音频播放器回调函数的状态时,就会被抛出无限重渲染。简化代码如下: import React, { useState} from 'react'; import { Audio }

我正在构建一个应用程序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

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

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

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


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

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

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


非常感谢你的回答,阅读你发布的链接,这看起来正是我需要的。今天晚些时候将尝试实现它。再次感谢您的帮助,在经过一点黑客攻击之后,您的建议使它能够正常工作。谢谢非常感谢你的回答,阅读你发布的链接,这看起来正是我需要的。今天晚些时候将尝试实现它。再次感谢您的帮助,在经过一点黑客攻击之后,您的建议使它能够正常工作。谢谢