react-native-snap-carousel

repository·master·Indexed 27 days ago

https://github.com/meliorence/react-native-snap-carousel

A swiper/carousel component for React Native compatible with Android and iOS. It supports multiple layouts (default, stack, tinder), parallax images via the ParallaxImage component, and custom interpolations using the Animated API. The library includes a Pagination component for dot indicators and provides RTL support. Version 3.9.1 requires React Native 0.43.x or higher to utilize FlatList for performant handling of large datasets.

Tokens
12.3K
Snippets
20
Records
61
Agent score
94%

What's inside react-native-snap-carousel

  1. Ensure compatible React Native version

    master

    For plugin versions >= 3.0.0, the minimum recommended React Native version is 0.43.x, as it introduced the FlatList component used by the plugin.

    If you use an older version of React Native, the component will automatically fall back to rendering a ScrollView (similar to setting the useScrollView prop to true). Note that ScrollView is not suitable for rendering a large number of items and may cause performance issues. For optimal performance, update React Native to a modern version to utilize FlatList.

  2. Migrate from version 2.x to 3.x

    master

    In version 3.x, the plugin is based on FlatList instead of ScrollView. Slides are no longer passed as direct children of the <Carousel /> component. Instead, you must use the data and renderItem props.

    Key changes:

    • Use the data prop to pass your array of items.
    • Use the renderItem prop to provide a function that returns the component for each item. The function receives an object containing {item, index}.
    • The key prop is no longer required for carousel items. If you need custom keys, provide a keyExtractor prop to the <Carousel /> component.
    // From (v2.x style):
    get slides () {
        return this.state.entries.map((entry, index) => {
            return (
                <View key={`entry-${index}`} style={styles.slide}>
                    <Text style={styles.title}>{ entry.title }</Text>
                </View>
            );
        });
    }
    
    render () {
        return (
            <Carousel
              sliderWidth={sliderWidth}
              itemWidth={itemWidth}
            >
                { this.slides }
            </Carousel>
        );
    }
    
    // To (v3.x style):
    _renderItem ({item, index}) {
        return (
            <View style={styles.slide}>
                <Text style={styles.title}>{ item.title }</Text>
            </View>
        );
    }
    
    render () {
        return (
            <Carousel
              data={this.state.entries}
              renderItem={this._renderItem}
              sliderWidth={sliderWidth}
              itemWidth={itemWidth}
            />
        );
    }
  3. Add horizontal margin between slides

    master

    To add extra horizontal space between slides (beyond the scale effect), apply paddingHorizontal to the slide's container.

    CRITICAL: The itemWidth prop must include this extra margin (twice the padding) to ensure correct layout calculations.

    const horizontalMargin = 20;
    const slideWidth = 280;
    const sliderWidth = Dimensions.get('window').width;
    // itemWidth MUST include the margin
    const itemWidth = slideWidth + horizontalMargin * 2;
    const itemHeight = 200;
    
    const styles = StyleSheet.create({
        slide: {
            width: itemWidth,
            height: itemHeight,
            paddingHorizontal: horizontalMargin
        },
        slideInnerContainer: {
            width: slideWidth,
            flex: 1
        }
    });
    
    // ... in render
    _renderItem ({item, index}) {
        return (
            <View style={styles.slide}>
                <View style={styles.slideInnerContainer} />
            </View>
        );
    }
    
    <Carousel
      renderItem={this._renderItem}
      sliderWidth={sliderWidth}
      itemWidth={itemWidth}
    />
  4. Implement navigation inside slides

    master

    To use navigation (e.g., this.props.navigation.navigate) inside your renderItem components, you must ensure the context of this is correctly passed.

    1. Bind renderItem in the Carousel component: renderItem={this._renderItem.bind(this)}.
    2. Pass the navigation prop through renderItem to your slide component.
    3. Access the navigation prop inside your slide component's render method.
    // 1. In Carousel
    <Carousel
        data={image1}
        renderItem={this._renderItem.bind(this)} 
        sliderWidth={equalWidth2}
        itemWidth={equalWidth5}
    />
    
    // 2. In _renderItem
    _renderItem ({item, index}) {
        return (
            <SliderEntry
                data={item}
                navigation={this.props.navigation}
            />
        );
    }
    
    // 3. Inside SliderEntry component
    render () {
        const { data, navigation } = this.props;
        return (
            <TouchableOpacity
                onPress={() => navigation.navigate('Feed')}
            >
                {/* ... */}
            </TouchableOpacity>
        );
    }
  5. Handle device rotation

    master

    To ensure slides re-center correctly when the device rotates, use the onLayout event on a wrapper View to update the sliderWidth and itemWidth in your component state.

    constructor(props) {
        super(props);
        this.state = {
            viewport: {
                width: Dimensions.get('window').width,
                height: Dimensions.get('window').height
            }
        };
    }
    
    render() {
        return (
            <View
                onLayout={() => {
                    this.setState({
                        viewport: {
                            width: Dimensions.get('window').width,
                            height: Dimensions.get('window').height
                        }
                    });
                }}
            >
                <Carousel
                    ref={c => { this.carousel = c; }}
                    sliderWidth={this.state.viewport.width}
                    itemWidth={this.state.viewport.width}
                    {...otherProps}
                />
            </View>
        );
    }
  6. Implement fullscreen slides

    master

    To create a fullscreen carousel effect, set the sliderWidth and itemWidth to the viewport width, use slideStyle for the width, and set inactiveSlideOpacity and inactiveSlideScale to 1 to prevent the preview/scaling effect.

    const { width: viewportWidth, height: viewportHeight } = Dimensions.get('window');
    
    export class MyCarousel extends Component {
        _renderItem ({item, index}) {
            return (
                <View style={{ height: viewportHeight }} /> // or { flex: 1 }
            );
        }
    
        render () {
            return (
                <Carousel
                  data={this.state.entries}
                  renderItem={this._renderItem}
                  sliderWidth={viewportWidth}
                  itemWidth={viewportWidth}
                  slideStyle={{ width: viewportWidth }}
                  inactiveSlideOpacity={1}
                  inactiveSlideScale={1}
                />
            );
        }
    }
  7. Animate dot colors in `<Pagination />`

    master

    To change the color of dots between active and inactive states, you have two options:

    1. Animated Transition: Specify both dotColor and inactiveDotColor.
      • Warning: When animating color transitions, the component cannot use the native driver for scale and opacity transitions due to React Native limitations. This may impact smoothness.
    2. Static Style Transition: Set { backgroundColor } within both dotStyle and inactiveDotStyle.

    It is recommended to use the second method (static styles) if you experience performance drops with the first method.

  8. Implement the `<ParallaxImage />` component

    master

    The <ParallaxImage /> component provides a parallax effect for images within a carousel by reacting to the current scroll position. It uses the native driver for high performance.

    To use it, you must:

    1. Set hasParallaxImages={true} on your <Carousel /> component.
    2. Capture the parallaxProps argument provided as the second argument to your renderItem() function.
    3. Spread {...parallaxProps} onto the <ParallaxImage /> component inside renderItem().

    Note: The source prop is required and is inherited from the standard React Native <Image /> component.

    import Carousel, { ParallaxImage } from 'react-native-snap-carousel';
    
    // ... inside your component
    
    _renderItem ({item, index}, parallaxProps) {
        return (
            <ParallaxImage
                source={{ uri: item.thumbnail }}
                parallaxFactor={0.4}
                {...parallaxProps}
            />
        );
    }
    
    render () {
        return (
            <Carousel
                data={this.state.entries}
                renderItem={this._renderItem}
                hasParallaxImages={true}
                // ... other props
            />
        );
    }
  9. Report a bug in react-native-snap-carousel

    master

    When reporting a bug, you must provide a high-quality report to ensure it is not closed without notice. A valid bug report must include:

    1. Environment Details: Specify versions for React, React Native, and react-native-snap-carousel, as well as the target platform (e.g., Android 6.0, iOS 10.3).
    2. Platform Specificity: Indicate if the bug is specific to iOS, Android, or both.
    3. Environment Context: State if the bug is reproducible in a production environment or only in debug mode.
    4. Expected vs. Actual Behavior: Describe what you expected to happen versus what actually occurred. Attach screenshots or screencasts to the Actual Behavior section.
    5. Reproducible Demo (Mandatory): Provide a link to a Snack example that is Minimal, Complete, and Verifiable (MCVE).
    6. Steps to Reproduce: Provide a specific, numbered sequence of steps that anyone can follow to see the issue in the provided demo.

    Before reporting, ensure you have:

    • Reviewed the project documentation and KNOWN_ISSUES.md.
    • Searched existing issues to confirm it hasn't been reported.
    • Verified that the issue is not a known React Native bug.