Summary of Problem
I'm using react-native-snap-carousel and it's not rendering properly. It only renders after being swiped and I need to it render when the screen initially renders. When I have the screen assigned to the initial route of my BottomTabNavigator or the initial route in my Stack Navigator in React Navigation, then the carousel renders perfectly. When I assign the exact same screen to any other route in a Stack Navigator, then it doesn't render the carousel until I swipe it.
I need to use the screen with the carousel as the second route in my Stack Navigator and I can't figure out how to make it work properly.
What I've tried
Code
Component with Carousel
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;
Styles for Component with Carousel
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
}
});
React Navigation Configuration
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"
}
);
Pictures outlining the problem
There is an experimental configuration (currently v3.8.4) - removeClippedSubviews
- which is set to true
by default. Setting it to false
fixed the issue form me.
I strongly recommend not using delays as it is not deterministic and changes per device.
Thanks to @auticcat who wrote this in a comment.
The same problem was coming on our project and a little trick help us . We have set default loading state to true and in componentDidMount set state to false to show Carousel
Try this , it may help you
state = { loading: true };
componentDidMount() {
setTimeout(() => {
this.setState({ loading: false });
}, 10);
}
render() {
if(this.state.loading) {
return null;
}
// return component render which contain Carousel
.........
}
我通过简单地使用 removeClippedSubviews={false} 解决了它
<Carousel
ref={c => {
_carousel = c;
}}
data={ENTRIES1}
renderItem={_renderItem}
sliderWidth={375}
itemWidth={100}
onSnapToItem={index => {
setSelectedStat(ENTRIES1[index]);
}}
/>
</
I think the problem lies here giving static height and width. Try calculating the height and width dynamically and then show it. Dynamically here means calculating the deivce height and width and then making calculation on them.
You can create your own custom carousel. The Carousel end result looks like this-
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 is the main logic used behind looped carousel. Here we are pushing the first item at last in the list again and then when scroll reaches at last position we are making the scrollview to scroll to first position as first and last element are same now and we scroll to first position with animation like this
this.scrollRef.current.scrollTo({ offset: 0, animated: false, nofix: true });
For further reference go through the link provided.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.