【问题标题】:react-native-snap-carousel doesn't render properlyreact-native-snap-carousel 无法正确渲染
【发布时间】:2020-01-07 20:52:17
【问题描述】:

问题总结

我正在使用 react-native-snap-carousel,但渲染不正确。它仅在被滑动后渲染,我需要在屏幕最初渲染时渲染它。当我将屏幕分配给我的 BottomTabNavigator 的初始路线或 React Navigation 中我的 Stack Navigator 中的初始路线时,轮播就会完美呈现。当我将完全相同的屏幕分配给 Stack Navigator 中的任何其他路线时,它不会呈现轮播,直到我滑动它。

我需要将带有轮播的屏幕用作 Stack Navigator 中的第二条路线,但我不知道如何使其正常工作。

我的尝试

  1. 我已尝试将其他所有内容都移出屏幕
  2. 我也尝试过从头开始创建一个新屏幕。
  3. 我已将屏幕作为 Stack Navigator 中的初始路由进行了测试,并且 它工作得很好,但我仍然无法让轮播在什么时候渲染 屏幕加载。
  4. 我还尝试切换到基于类的反应组件,并且 没有帮助。

代码

带有轮播的组件

import React, { useState } from "react";
import { View, Text } from "react-native";
import { useDispatch } from "react-redux";
import styles from "./StatSelectorStartComp.style";
import HeaderText from "~/app/Components/HeaderText/HeaderText";
import Carousel from "react-native-snap-carousel";
import LargeButton from "~/app/Components/Buttons/LargeButton/LargeButton";
import NavigationService from "~/app/services/NavigationService";
import { saveStartCompStatCategory } from "~/app/Redux/actions/dailyCompActions";

const StatSelectorStartComp = ({}) => {
  const dispatch = useDispatch();
  const ENTRIES1 = ["Kills", "Wins", "K/D", "Win %"];
  const [selectedStat, setSelectedStat] = useState(ENTRIES1[0]);

  const _renderItem = ({ item, index }) => {
    return (
      <View style={styles.slide}>
        <Text style={styles.compSelectStatCarousel}>{item}</Text>
      </View>
    );
  };

  return (
    <View style={styles.container}>
      <View style={styles.headerTextView}>
        <HeaderText header={"Configure Competition"} />
      </View>
      <Text style={styles.h5Secondary}> Which stat will you track?</Text>
      <View style={styles.selectStatView}>
        <Text style={styles.mediumGreyedOut}>Most {selectedStat} Wins</Text>
        <Carousel
          ref={c => {
            _carousel = c;
          }}
          data={ENTRIES1}
          renderItem={_renderItem}
          sliderWidth={375}
          itemWidth={100}
          onSnapToItem={index => {
            setSelectedStat(ENTRIES1[index]);
          }}
        />
      </View>
      <View style={styles.buttonView}>
        <LargeButton
          onPress={() => {
            dispatch(saveStartCompStatCategory(selectedStat));
            NavigationService.navigate("CompAddFriends");
          }}
          buttonText="Add Friends"
        />
      </View>
    </View>
  );
};

export default StatSelectorStartComp;

带有轮播的组件样式

import { StyleSheet } from "react-native";
import { backgroundColor } from "~/app/Constants";
import {
  h5Secondary,
  mediumGreyedOut,
  compSelectStatCarousel
} from "~/app/FontConstants";

export default StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "space-between",
    backgroundColor
  },
  headerTextView: {
    flex: 1
  },
  h5Secondary,
  selectStatView: {
    flex: 3
  },
  mediumGreyedOut,
  compSelectStatCarousel,
  buttonView: {
    flex: 2
  }
});

反应导航配置

const StartCompStack = createStackNavigator({
  StartFriendsComp: {
    screen: StartFriendsComp
  },
  StatSelectorStartComp: {
    screen: CarouselTest
  },
  CompAddFriends: {
    screen: CompAddFriends
  },
  FinalCompScreen: {
    screen: FinalCompScreen
  }
});

const ProfileStack = createStackNavigator({
  Profile: {
    screen: ProfileScreen
  },
  Settings: {
    screen: SettingsScreen
  }
});

const BottomTabNav = createBottomTabNavigator(
  {
    Home: {
      screen: HomeScreen
    },
    Competitions: {
      screen: Competitions
    },
    StartComp: {
      screen: StartCompStack,
      navigationOptions: () => ({
        tabBarVisible: false
      })
    },
    CompScreen: {
      screen: CompScreen
    },
    Friends: {
      screen: FriendsDrawer
    },
    Profile: {
      screen: ProfileStack
    },
    FacebookFriendsList
  },
  {
    tabBarComponent: CustomTabNav,
    initialRouteName: "Home" 
  }
);

概述问题的图片

屏幕加载时,轮播不呈现

在旋转木马上滑动后

【问题讨论】:

    标签: javascript reactjs react-native react-native-snap-carousel


    【解决方案1】:

    有一个实验配置(当前为 v3.8.4) - removeClippedSubviews - 默认设置为 true。将其设置为 false 解决了我的问题。

    我强烈建议不要使用延迟,因为它不是确定性的,并且会因设备而异。

    感谢@auticcat 在评论中写了这篇文章。

    【讨论】:

    • 谢谢,真的很有帮助。我对此很好奇。为什么当我们将标志设置为 false 时,它​​会起作用?
    • 我相信这个功能的目的是防止在当前视图之外(或被裁剪)的组件的冗余渲染。但这可能不是您需要的,具体取决于您对轮播的使用情况。
    【解决方案2】:

    我们的项目也遇到了同样的问题,一个小技巧可以帮助我们。我们已将默认加载状态设置为 true,并且在 componentDidMount 中将状态设置为 false 以显示 Carousel

    试试这个,可能对你有帮助

    state = { loading: true };
    
      componentDidMount() {
        setTimeout(() => {
          this.setState({ loading: false });
        }, 10);
      }
      render() {
        if(this.state.loading) {
          return null;
        }
    
        // return component render which contain Carousel
        ......... 
      }
    
    

    【讨论】:

    • 感谢@Mehran Khan!它工作得很好!超时 10 我仍然遇到问题,但我将其更改为 100 并且它运行良好。在您做出回应之前,我感觉这可能是一个反应生命周期问题,在看到您的解决方案后,我真的认为是这样。任何猜测为什么会这样?如果我弄清楚实际问题是什么,我会告诉你的!我还在他们的 github 上打开了一个问题
    • 我通过简单地使用removeClippedSubviews={false}解决了它
    【解决方案3】:

    我通过简单地使用 removeClippedSubviews={false}

    解决了它

    【讨论】:

      【解决方案4】:
      <Carousel
                ref={c => {
                  _carousel = c;
                }}
                data={ENTRIES1}
                renderItem={_renderItem}
                sliderWidth={375}
                itemWidth={100}
                onSnapToItem={index => {
                  setSelectedStat(ENTRIES1[index]);
                }}
              />
            </
      

      我认为问题在于给出静态高度和宽度。尝试动态计算高度和宽度,然后显示它。这里的动态是指计算设备的高度和宽度,然后对它们进行计算。

      【讨论】:

      • 感谢您的建议。为什么你认为问题在于静态宽度和高度?我尝试更改它们,但没有帮助。说到底就算是动态计算的,还是用一个数字来设置宽高吧?
      • 一个组件可能被另一个组件覆盖
      • 我不认为是这种情况,因为当它不在堆栈导航器中时它会正确呈现。我听从了 Mehran 的建议,效果很好。不过感谢您的帮助!
      【解决方案5】:

      您可以创建自己的自定义轮播。 Carousel 最终结果如下所示-

           goToNextPage = () => {
          const childlenth = this.getCustomData().length;
          selectedIndex = selectedIndex + 1;
          this.clearTimer();
          if (selectedIndex === childlenth) {
              this.scrollRef.current.scrollTo({ offset: 0, animated: false, nofix: true });
              selectedIndex = 1;
          }
          this.scrollRef.current.scrollTo({
              animated: true,
              x: this.props.childWidth * selectedIndex,
          });
          this.setUpTimer();
      }
      
      // pushing 1st element at last
       getCustomData() {
          const {data} = this.props;
          const finaldata = [];
          finaldata.push(...data);
          finaldata.push(data[0]);
          return finaldata;
      }
      

      这是循环轮播背后使用的主要逻辑。 在这里,我们最后再次推送列表中的第一个项目,然后当滚动到达最后一个位置时,我们使滚动视图滚动到第一个位置,因为第一个和最后一个元素现在相同,我们滚动到第一个位置,像这样的动画

      this.scrollRef.current.scrollTo({ offset: 0, animated: false, nofix: true });
      

      如需进一步参考,请访问提供的链接。

      https://goel-mohit56.medium.com/custom-horizontal-auto-scroll-looped-carousel-using-scrollview-42baa5262f95

      【讨论】:

      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
      猜你喜欢
      • 1970-01-01
      • 2020-09-03
      • 2020-03-18
      • 2019-01-27
      • 1970-01-01
      • 2017-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多