在 useEffect 内反应原生 setState 不触发重新渲染

时间:2021-06-12 13:15:12

标签: react-native react-hooks

我正在尝试构建一个使用 Expo AV 播放音频文件的组件。在音频可用之前,我希望组件以降低的不透明度(不透明度 = 0.2)进行渲染。音频加载后,我希望按钮完全不透明。我尝试使用 useEffect 钩子(没有依赖项,只想在组件安装时加载一次音频文件)和一个名为“isLoaded”的状态变量来实现这一点。代码如下:

const AudioPlayer = ({ containerStyle }) => {
  const [isPlaying, setIsPlaying] = useState(false);
  const [voice, setVoice] = useState(undefined);
  const [isLoaded, setIsLoaded] = useState(false);

  useEffect(() => {
    const fetchSound = async () => {
      const { sound } = await Audio.Sound.createAsync(DEFAULT_AUDIO_PATH);
      setVoice(sound);
      setIsLoaded(true);
    }
    fetchSound();
  }, []);

  const playSound = async () => {
    if (isLoaded) {
      try {
        voice.setOnPlaybackStatusUpdate(status => {
          status.didJustFinish ? setIsPlaying(false) : null;
        });
        setIsPlaying(true);
        await voice.replayAsync();
      } catch (e) {
        console.log(e);
      }
    }
  }

  return (
    <TouchableOpacity
      style={isLoaded ? [styles.container, containerStyle] : [styles.unloaded, containerStyle]}
      onPress={playSound}>
      <View style={styles.icon_wrapper}>
        <FontAwesome
          name={isPlaying ? 'volume-up' : 'play'}
          style={styles.icon}
        />
      </View>
    </TouchableOpacity>
  );
}

组件不透明度在我按下按钮之前不会改变,此时组件开始按预期呈现,因此很明显 isLoaded 状态是从 useEffect 钩子设置的。我在这里做错了什么?

1 个答案:

答案 0 :(得分:0)

对于任何有类似问题的人 - TouchableOpacity 似乎存在一个错误,即对元素所做的任何不透明度更改仅在按下组件时触发。

要解决此问题,只需将 TouchableOpacity 更改为 Pressable。