【问题标题】:React Native - useRef for an array (Expo)React Native - 数组的 useRef (Expo)
【发布时间】:2021-10-23 08:51:16
【问题描述】:

一直在应用程序上使用 Expo 和 RN,但我遇到了一个问题。我正在使用Expo Video 制作照片/视频库。问题是,如果数组中有超过 1 个视频,则只会播放最后一个视频(useRef 有问题)。而且我找不到为每个人创建一个 ref 的方法。

我尝试过但成功了一半的解决方案:我创建了一个VideoComponent(作为一个函数,然后在返回时添加),每个组件都有自己的useRefuseState 用于播放在组件内部,每个视频/状态都有一个不同的useRef/useState。它工作正常。但问题是当其他状态发生变化时(例如,用户按下类似)。每当状态更改并重新渲染时,整个视频都会重置到开头。哪个不好。 如果正常执行其他组件的状态更改时的视频重置不会影响视频(一个useRef / state),但正如我所说,它只播放最后一个组件,这是不行的。

import React, { useRef, useState } from 'react';
import {
  SafeAreaView,
  View,
  FlatList,
  StyleSheet,
  Text,
  StatusBar,
} from 'react-native';

function App(props) {
  const [allData, setAllData] = useState([
    {
      medias: [
        { link: 'https://link.com/link1.avi', mediaExtension: 'avi' },
        { link: 'https://link.com/link2.jpg', mediaExtension: 'jpg' },
        { link: 'https://link.com/link3.mov', mediaExtension: 'mov' },
      ],
      name: 'Name',
      description: 'description',
    },
  ]);
  const video = useRef(null);
  const [status, setStatus] = useState({});

  return (
    <View style={{}}>
      <FlatList
        horizontal
        data={allData}
        renderItem={({ item }) => (
          <View style={{}}>
            {item.medias.map((item) => (
              <View>
                {item.mediaExtension === 'mov' || 'avi' || 'WebM' ? (
                  <View style={{ flex: 1 }}>
                    <TouchableOpacity
                      onPress={() =>
                        video.isPlaying
                          ? video.current.pauseAsync()
                          : video.current.playAsync()
                      }>
                      <Video
                        ref={video}
                        style={{ alignSelf: 'center' }}
                        source={{
                          uri: item.link,
                        }}
                        onPlaybackStatusUpdate={(status) =>
                          setStatus(() => status)
                        }
                      />
                    </TouchableOpacity>
                  </View>
                ) : (
                  <Image style={{}} source={{ uri: item.link }} />
                )}
              </View>
            ))}
          </View>
        )}
      />
    </View>
  );
}

export default App;

【问题讨论】:

    标签: javascript arrays reactjs react-native react-hooks


    【解决方案1】:

    据我了解,您想创建一个 FlatList 视频,而 onScroll 您想暂停它。这可以实现如下所示

    另外,这里有一个Working Example

    import * as React from 'react';
    import { Text, View, StyleSheet, FlatList } from 'react-native';
    import Constants from 'expo-constants';
    import VideoPlayer from './components/VideoPlayer';
    
    const Videos = [
      {
        _id: 1,
        source: require('./assets/videoplayback.mp4'),
      },
      {
        _id: 2,
        source: require('./assets/videoplayback.mp4'),
      },
      {
        _id: 3,
        source: require('./assets/videoplayback.mp4'),
      },
      {
        _id: 4,
        source: require('./assets/videoplayback.mp4'),
      },
      {
        _id: 5,
        source: require('./assets/videoplayback.mp4'),
      },
      {
        _id: 6,
        source: require('./assets/videoplayback.mp4'),
      },
    ];
    
    export default function App() {
      const [Viewable, SetViewable] = React.useState([]);
      const ref = React.useRef(null);
    
      const onViewRef = React.useRef((viewableItems) => {
        let Check = [];
        for (var i = 0; i < viewableItems.viewableItems.length; i++) {
          Check.push(viewableItems.viewableItems[i].item);
        }
        SetViewable(Check);
      });
    
      const viewConfigRef = React.useRef({ viewAreaCoveragePercentThreshold: 80 });
    
      return (
        <View style={styles.container}>
          <FlatList
            data={Videos}
            keyExtractor={(item) => item._id.toString()}
            renderItem={({ item }) => <VideoPlayer {...item} viewable={Viewable} />}
            ref={ref}
            onViewableItemsChanged={onViewRef.current}
            viewabilityConfig={viewConfigRef.current}
          />
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        paddingTop: Constants.statusBarHeight,
        backgroundColor: '#ecf0f1',
      },
    });
    

    VideoPLayer 组件看起来像这样

    import * as React from 'react';
    import { Text, View, StyleSheet, Dimensions } from 'react-native';
    import Constants from 'expo-constants';
    import { Video, AVPlaybackStatus } from 'expo-av';
    
    export default function VideoPlayer({ viewable, _id, source }) {
      const video = React.useRef(null);
    
      React.useEffect(() => {
        if (viewable) {
          if (viewable.length) {
            if (viewable[0]._id === _id) {
              video.current.playAsync();
            } else {
              video.current.pauseAsync();
            }
          } else {
            video.current.pauseAsync();
          }
        } else {
          video.current.pauseAsync();
        }
      }, [viewable]);
    
      return (
        <View style={styles.container}>
          <Video
            ref={video}
            source={source}
            rate={1.0}
            volume={1.0}
            resizeMode={'contain'}
            isLooping
            shouldPlay
            style={styles.video}
          />
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        width: Dimensions.get('window').width,
        marginBottom: 100,
        marginTop: 100,
      },
      video: {
        width: Dimensions.get('window').width,
        height: 300,
      },
    });
    

    【讨论】:

    • 您的示例工作正常,但我找不到将它实现到我自己的 FlatList 的方法(如您所见,我有一个带有图像/视频作为数据的 flatList,我在其中检查如果扩展名是视频或图像)。你的例子并没有让我这样做
    • 我也不希望它被滚动。我只想要一个可以暂停/播放的按钮
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-07
    • 2020-03-15
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多