AKHIL OMAR
AKHIL OMAR

Reputation: 49

React Native Flip Card not Working on flip

I am trying to make a flip card game. I used GestureFlipView for flip card animation. I want to display these flip card in 3X3 grid and for that I have used from react native. But the problem occurs that cards are not getting flipped and it is showing vague behaviour as well. Just the last card working fine and other cards are doing unpredictable behaviour.

Github Repo: https://github.com/akhilomar/React-Native-Number-Game

CardScreen: https://i.sstatic.net/Cliww.png

Card Component

import {View, Text, SafeAreaView, TouchableOpacity} from 'react-native';
import GestureFlipView from 'react-native-gesture-flip-card';

const Cards = (props) => {

    const [flipType, setFlip] = useState('left');

    useEffect(() => {

    })


    const renderFront = () => {
        return(
            <TouchableOpacity onPress = {() => {
                this.flipView.flipRight() 
                setFlip('right');
                console.log("Pressed" + `${props.val}`)
        
        }} >
            <View style = {{backgroundColor:'red', width: 100, height: 100, alignItems: 'center', justifyContent: 'center'}}>
                <Text style = {{color: "white", fontSize: 20}}>Swipe Me</Text>
                

            </View>
            </TouchableOpacity>
        );
    };

    const renderBack = () => {
        return(
        <View style = {{backgroundColor:'blue', width: 100, height: 100, alignItems: 'center', justifyContent: 'center'}}>
            <Text style = {{color: "white", fontSize: 30}}>{props.val}</Text>
            {/* <TouchableOpacity onPress = {() => {
                (flipType === 'left') ? this.flipView.flipRight() : this.flipView.flipLeft();
                setFlip((flipType === 'left') ? 'right' : 'left');
        
        }}  style = {{padding: 10, backgroundColor: 'purple', width: 100, height: 40, alignItems: 'center', justifyContent: 'center'}}>
                <Text style = {{color: 'white'}}>Reverse</Text>
            </TouchableOpacity> */}

        </View>
        );
    };
    //ref = {(ref) => this.flipView = ref}

    return(
        <SafeAreaView style = {{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
            <GestureFlipView ref = {(ref) => this.flipView = ref}  width={300} height = {500}>
                {renderFront()}
                {renderBack()}
            </GestureFlipView>
        </SafeAreaView>
    );
}

export default Cards;```

**Card List Component**

```import React from 'react';
import {SafeAreaView, View, FlatList, Dimensions, StyleSheet } from 'react-native';
import Cards from './Cards';

const CardScreen = () => {

    // const data = ['1','2','3','4','5','6','7','8','9'];

    const DATA = [
      {
        id: '1',
        title: '1',
      },
      {
        id: '2',
        title: '2',
      },
      {
        id: '3',
        title: '3',
      },
      {
        id: '4',
        title: '4',
      },
      {
        id: '5',
        title: '5',
      },
      {
        id: '6',
        title: '6',
      },
      {
        id: '7',
        title: '7',
      },
      {
        id: '8',
        title: '8',
      },
      {
        id: '9',
        title: '9',
      }
      
    ];

      const Shuffle = (arr1) => {
        var ctr = arr1.length, temp, index;
        while (ctr > 0) {
            index = Math.floor(Math.random() * ctr);
            ctr--;
            temp = arr1[ctr];
            arr1[ctr] = arr1[index];
            arr1[index] = temp;
        }
        return arr1;
      }

      const numColumns = 3;
      const size = Dimensions.get('window').width/numColumns;
      const styles = StyleSheet.create({
        itemContainer: {
          width: size,
          height: size,
        },
        item: {
          flex: 1,
          margin: 3,
          backgroundColor: 'lightblue',
        }
      });
    
    return(
      <>
        <FlatList
            data={DATA}
            renderItem={({ item }) => (
                <View style={styles.itemContainer}>
                    <Cards val = {item.value}/>
                </View>
            )}
            keyExtractor={item => item.id}
            numColumns={numColumns} />

          {/* {
            data.map((index, item) => {
              return(
              
              <View style={styles.itemContainer}>
                    <Cards val = {item}/>
              </View>
              );
            })
          } */}
      </>
    );
}

export default CardScreen;```

Upvotes: 1

Views: 1044

Answers (2)

joachimwedin
joachimwedin

Reputation: 1564

The primary cause of your troubles is the fact that you are using a this reference within a functional component. As explained here, the value of this will be determined by how the function is called, and might even be undefined. A more reliable approach of using this is from a class context. For React, that means using a class component, rather than a functional component, which is what is being used here. You can read about function and class components here.

Something else to consider is if a FlatList is appropriate here. Typically, this component is used to improve performance for rendering large lists. Instead of using a FlatList, I would recommend using something simpler, such as a set of View components to draw the cards. Here is a complete example based on your code:

import React, { useState } from 'react';
import { View, Dimensions, StyleSheet, Text, TouchableOpacity } from 'react-native';
import GestureFlipView from 'react-native-gesture-flip-card';

const Card = (props: any) => {

  const [flipType, setFlip] = useState('left');

  let flipView: any;
  const onFrontPress = () => {
    flipView.flipRight()
    setFlip('right');
  }
  const cardDimensions = { width: 0.9 * props.size, height: 0.9 * props.size };

  const renderFront = () => {
    return (
      <TouchableOpacity onPress={onFrontPress} style={[styles.front, cardDimensions]}>
        <Text style={styles.frontText}>Swipe Me</Text>
      </TouchableOpacity>
    );
  };

  const renderBack = () => {
    return (
      <View style={[styles.back, cardDimensions]}>
        <Text style={styles.backText}>{props.val}</Text>
      </View>
    );
  };

  return (
    <GestureFlipView ref={(ref) => flipView = ref} width={props.size}     height={props.size}>
      {renderFront()}
      {renderBack()}
    </GestureFlipView>
  );
}

const CardRow = () => {
  const size = Dimensions.get('window').width / 3;
  return (
    <View style={styles.rowContainer}>
      <Card size={size} />
      <Card size={size} /{ width: 0.9 * props.size, height: 0.9 * props.size }>
      <Card size={size} />
    </View>
  );
}

const CardScreen = () => {
  return (
    <View style={styles.container}>
      <CardRow />
      <CardRow />
      <CardRow />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flexDirection: 'column',
    flex: 1,
  },
  rowContainer: {
    flexDirection: 'row',
    justifyContent: 'space-evenly',
  },
  back: {
    backgroundColor: 'blue',
    alignItems: 'center',
    justifyContent: 'center'
  },
  backText: {
    color: "white",
    fontSize: 30
  },
  front: {
    backgroundColor: 'green',
    alignItems: 'center',
    justifyContent: 'center',
  },
  frontText: {
    color: "white",
    fontSize: 20
  }

});

export default CardScreen;

Upvotes: 1

Ahmed Gaber
Ahmed Gaber

Reputation: 3966

You need to use ref correctly. you can Read about it here

const Cards = (props) => {
  //first define ref
  const flipViewRef = React.useRef();


  //in onPress use it like this
  <TouchableOpacity onPress = {() => {
        flipViewRef.current.flipRight() 
        ...     
 }} >

  //in GestureFlipView assign it like this
  <GestureFlipView ref={flipViewRef} />
  


}

Upvotes: 1

Related Questions