简体   繁体   English

React Native - 数组的 useRef (Expo)

[英]React Native - useRef for an array (Expo)

Been using Expo and RN on an app, but I'm stuck with a problem.在应用程序上使用 Expo 和 RN,但我遇到了一个问题。 I'm using Expo Video to make a photo/video gallery.我正在使用Expo 视频制作照片/视频画廊。 The problem is, if I have more than 1 video in the array, only the last one will play (problem with useRef).问题是,如果数组中有超过 1 个视频,则只有最后一个会播放(useRef 的问题)。 And I couldn't find a way to create a ref for each one of them.而且我找不到为每个人创建参考的方法。

Solutions that I've tried and half worked: I created a VideoComponent (as a function then added on return), and each component had its own useRef and useState for playing inside the component a different useRef/useState for video/status for each.我已经尝试过并且成功了一半的解决方案:我创建了一个VideoComponent (作为 function 然后在返回时添加),并且每个组件都有自己的useRefuseState用于在组件内部播放不同的useRef/useState用于每个视频/状态。 It worked okay-ish.它工作正常。 But the problem was when other states changed (user presses like, for example).但问题是当其他状态发生变化时(例如,用户按下)。 Whenever a state changes, and rerenders, the whole video reset to the beginning.每当 state 发生变化并重新呈现时,整个视频都会重置到开头。 Which is not ok.这不好。 The video reset on state change of other components doesn't affect the video if doing it normally (one useRef/state) but as I said, It's only playing the last component, which is not okay. state 上的视频重置如果正常进行(一个 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;

As far as I understand, you want to create a FlatList of Videos, and onScroll you want to pause it.据我了解,您想创建一个 FlatList of Videos,并且onScroll您想暂停它。 This can be implemented as shown below这可以如下所示实现

Also, here is a Working Example for this此外,这是一个工作示例

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',
  },
});

and VideoPLayer component looks like thisVideoPLayer组件看起来像这样

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,
  },
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM