ReactNative; How to rerender component flipcard after update state - react-native

I use flipcard(show front - back) to show value but when I change value to show the new one,Flipcard don't back to the front. It still on same page(but value changed)
Example
data1:Front is "A" ,Back is "B"
data2:Front is "X" ,Back is "Y"
I flip A >> B ,Now on flipcard show "B" after that,I update value. Flipcard show "Y" it's not show "X",I have to flip again to "X" . But, I want to show the front of flipcard every new data. How can I do it?
Nextword() {
this.setState({ count: this.state.count + 1 });
}
render() {
return <View>
<View>
<CardFlip ref={(card) => this.card = card} >
<TouchableOpacity onPress={() => this.card.flip()}>
<Text>{this.state.info[this.state.count].item1}</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.card.flip()} >
<Text>{this.state.info[this.state.count].item2}</Text>
</TouchableOpacity>
</CardFlip>
</View >
<View>
<Button title="PRESS1" onPress={this.Nextword.bind(this)}></Button>
</View>

According to the documentation example of react-native-card-flip I just give a style like this to CardFlip component:
style={{
width: 320,
height: 470,
}}
and fix the issue and card flipped.
below the entire code I try:
<View>
<CardFlip
style={{
width: 320,
height: 470,
}}
ref={(card) => (this.card = card)}>
<TouchableOpacity
onPress={() => this.card.flip()}
style={{height: 100, width: 100, backgroundColor: 'green'}}>
<Text>{this.state.info[this.state.count].item1}</Text>
</TouchableOpacity>
<TouchableOpacity
style={{height: 100, width: 100, backgroundColor: 'green'}}
onPress={() => this.card.flip()}>
<Text>{this.state.info[this.state.count].item2}</Text>
</TouchableOpacity>
</CardFlip>
</View>
see the documentation example here: https://github.com/lhandel/react-native-card-flip/blob/master/Example/App.js

Related

Select and deselect multiple Items in flatlist performance issue

Displaying more than 200+ images in the flatlist and make the user to select or deselect by clicking an image. So, when the user is clicks a image, Need to show the check-circle icon on the image. Similarly, when the user is deselect the selected image, need to remove the icon. I got two arrays images[] and selectedImagesId[]. Whenever the user selects an image, the image id will be pushed into selectedImagesId array. By the way, Iam showing the icon if the rendered image id avaliable in the selectedImagesId. The problem here is, it takes so long to display or remove the icon.
<FlatList
data={props.images}
extraData={selectedImagesId}
initialNumToRender={10}
refreshing={true}
removeClippedSubviews={true}
maxToRenderPerBatch={1}
windowSize={7}
showsVerticalScrollIndicator={false}
numColumns={3}
keyExtractor={(item) => item.id.toString()}
renderItem={(itemData) => <RenderData itemData={itemData} />}
>
const RenderData = ({ itemData }) => (
<View>
<TouchableOpacity
activeOpacity={0.8}
style={{
width: width / 3.5,
height: height / 7,
padding: 2,
}}
onPress={() => {
console.log('pressed');
if (props.selectedImages.includes(itemData.item.uri)) {
const index = props.selectedImages.indexOf(itemData.item.uri);
if (index > -1) {
props.removeImageandId(index, itemData.item.id);
}
} else {
props.selectImageandId(itemData.item.uri, itemData.item.id);
}
}}>
<Image
style={{ width: '100%', height: '100%' }}
source={{
uri: itemData.item.uri,
}}
/>
{selectedImagesId.includes(itemData.item.id) && (
<AntDesign
name='checkcircle'
size={24}
color='white'
style={{ position: 'absolute', bottom: 5, right: 15 }}
/>
)}
</TouchableOpacity>
<Text style={{ backgroundColor: 'red', fontSize: 25 }}>
{render.current++}
</Text>
</View>
);
You can Refer This article
It will guide you on how to render Only particular selected components that change.
not the Whole flatList components.
so, that based Only selected particular component you can remove the icon. not whole flatList Re-render.

Filtered object array length in React Native

I have an object array as shown below:
data = [
{
"shelf_name" : "Shelf A",
"shelf_size" : "9",
"shelf_color" : "red",
"shelf_height": "100",
"shelf_width" : "150",
},
{
"shelf_name" : "Shelf A",
"shelf_size" : "4",
"shelf_color" : "blue",
"shelf_height": "150",
"shelf_width" : "170",
},
{
"shelf_name" : "Shelf B",
"shelf_size" : "6",
"shelf_color" : "yellow",
"shelf_height": "175",
"shelf_width" : "200",
}
]
I am using the filter function to filter the data by shelf_name and then display the data on the screen. My return function looks like this:
return (
<View style={styles.container}>
{loading ? (
<ActivityIndicator size="large" color={COLORS.blue} />
) : (
<View style={styles.container1}>
<View style={{height: 250}}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.scrollViewStyle}>
{data
.filter(function (shelfName) {
return shelfName.shelf_name === 'Shelf A';
})
.map((item, index) => {
<View key={index} style={styles.productView}>
<Text
style={{
alignSelf: 'flex-start',
fontWeight: 'bold',
marginLeft: 5,
}}>
{item.product_name}
</Text>
<Text>Shelf Size: {item.shelf_size}</Text>
<Text>
Shelf Height: {item.shelf_height}
</Text>
<Text>
Shelf Width: {item.shelf_width}
</Text>
<Text>
Shelf Color: {item.shelf_color}
</Text>
</View>;
})}
</ScrollView>
</View>
</View>
</View>
Current Output:
If the data exists after the filter function it is displayed properly. If the data does not exists nothing is displayed on the screen
What I am trying to achieve:
Show the data if the data exists or else show a message that "The data does not exist". To achieve this I tried to check the length of the object after the filter function by using Object.keys(data).length inside an if condition. But, I am unable to do so. Please let me know how do I achieve this.
What I am trying to achieve: Show the data if the data exists or else show a message that "The data does not exist". To achieve this I tried to check the length of the object after the filter function by using Object.keys(data).length inside an if condition. But, I am unable to do so. Please let me know how do I achieve this.
Have you tried using data.length? By what it look like your data is always an array, so you don't need the Object.keys. In fact using it will always be true because beside the length key an array object have many other functions.
Try something like...
const filteredData = data.filter(function (shelfName) {
return shelfName.shelf_name === 'Shelf A';
});
return (
<View style={styles.container}>
{loading ? (
<ActivityIndicator size="large" color={COLORS.blue} />
) : (
<View style={styles.container1}>
<View style={{height: 250}}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.scrollViewStyle}>
{!filteredData.length && <Text>The data does not exist</Text>}
{filteredData
.map((item, index) => {
<View key={index} style={styles.productView}>
<Text
style={{
alignSelf: 'flex-start',
fontWeight: 'bold',
marginLeft: 5,
}}>
{item.product_name}
</Text>
<Text>Shelf Size: {item.shelf_size}</Text>
<Text>
Shelf Height: {item.shelf_height}
</Text>
<Text>
Shelf Width: {item.shelf_width}
</Text>
<Text>
Shelf Color: {item.shelf_color}
</Text>
</View>;
})}
</ScrollView>
</View>
</View>
</View>

How can I animate a component to another component?

I want to animate a card to the game table.
How can I move the component of the card to that of the game table?
Onpress
Result
I tried to with:
this.state.cards.find(c => c.id == id).ref.layout.animate({
from: { bottom: -20, bottom: 0 },
to: { bottom: 416, bottom: 196 },
But the .animate method is based on the x and y of the parent view and not on the x y of the screen.
Here is the part of my code:
<View style={styles.board}>
<ImageBackground source={require('../../assets/ornement.png')} resizeMode='contain' style={styles.ornement}>
<View onLayout={ref => this.test = ref}>
<Text style={boardStyle.message}>Test</Text>
</View>
<View style={boardStyle.boardContent} ref={event => this.view = event}>
{this.state.board.map((r, i) => <Image key={i} style={boardStyle.image} resizeMode='contain' source={CardUtils.PathOfimgCard(r.fullName)} />
)}
</View>
</ImageBackground>
</View>
<View style={styles.deck}>
{this.state.deck.map((r, i) =>
<Card onRef={(ref) => this.state.cards.push({ id: r.id, ref: ref })} key={i} ctx={r} action={this.play} select={this.state.cardSelect.find(c => c.id == r.id) != null} id={r.id} path={CardUtils.PathOfimgCard(r.fullName)} style={deckStyle} />
)}
</View>
The Card component:
<Animatable.View ref={event => this.layout = event} iterationCount={3} delay={5000} direction="alternate" style={this.props.style.touchZone} >
<TouchableOpacity onPress={() => this.props.action(this.props.id)} >
<View ref={event => this.view = event}>
<ImageBackground source={this.props.path} style={this.props.select ? this.props.style.active : this.props.style.image} resizeMode='contain' >
{!this.props.ctx.canPlay ? <Image style={[this.props.select ? this.props.style.active : this.props.style.image, styles.image]} resizeMode='contain' source={require('../../assets/black.png')} /> : <Image></Image>}
</ImageBackground>
</View>
</TouchableOpacity>
</Animatable.View>
thank you in advance

How to close swipe item in react-native?

I have this code (get from native-base example) that is working fine. But after click on either sides (right or left), the 'swipe' still open. I know that there is a method called closeRow(), but I don't know how to apply in this case.
Left button is for 'split' item into 2 or more, while right button is to delete current item. What I need is to close all opened rows in this list. Why all? Because in the case of 'delete' function, the current item is deleted in the right way, but the next-one get right button opened (since it's the same 'index' of list, even if the item itself is different).
This is my current code:
<Container style={styles.container}>
<Header>
<Left>
<Button transparent onPress={() => this.props.navigation.goBack()}>
<Icon name="arrow-back" />
</Button>
</Left>
<Body>
<Title>{translate("title", { ...i18n_opt, name })}</Title>
</Body>
</Header>
<Content>
<Modal
isVisible={this.state.visibleModal === true}
animationIn={"slideInLeft"}
animationOut={"slideOutRight"}
>
{this._renderModalContent()}
</Modal>
<View style={styles.line}>
<View style={{ flex: 2 }}>
<Text style={[styles.alignCen, styles.headerTitle]}>
{translate("lap", { ...i18n_opt })}
</Text>
</View>
<View style={{ flex: 10 }}>
<Text style={[styles.alignCen, styles.headerTitle]}>
{translate("time", { ...i18n_opt })}
</Text>
</View>
<View style={{ flex: 3 }}>
<Text
style={[
{ paddingRight: 10 },
styles.alignRig,
styles.headerTitle
]}
>
{translate("diff", { ...i18n_opt })}
</Text>
</View>
</View>
<List
enableEmptySections
dataSource={laps2}
ref={c => {
this.component = c;
}}
renderRow={data => <PersonalRankItem dados={data} />}
renderLeftHiddenRow={data => (
<Button
full
onPress={() => {
this.setState({
...this.state,
visibleModal: true,
cur_tx_id: tx_id,
cur_lap: data.lap
});
}}
style={{
backgroundColor: "#CCC",
flex: 1,
alignItems: "center",
justifyContent: "center",
marginBottom: 6
}}
>
<MaterialCommunityIcons
name="arrow-split-vertical"
size={20}
color="#5e69d9"
/>
</Button>
)}
renderRightHiddenRow={(data, secId, rowId, rowMap) => (
<Button
full
danger
onPress={_ => {
//alert("Delete");
//console.log("Data.lap:",data.lap);
dispatchDeleteLap(tx_id, data.lap, true);
}}
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
marginBottom: 6
}}
>
<Icon active name="trash" size={20} />
</Button>
)}
leftOpenValue={70}
rightOpenValue={-70}
/>
</Content>
</Container>
Goal
You need to close all the rows, each time one of row side button clicked. The next problem is when item deleted, the next row is opened even the content is different.
How?
All you need is first, collect the ref of each rows and then when the button clicked, trigger the closeRow method of all ref's row. And the important part, make your row key persistent and unique to avoid problem like in your case.
Quick Code Sample
class Screen extends Component {
constructor(props) {
super(props);
this._rowRefs = [];
}
// this is used to collect row ref
collectRowRefs = (ref) => {
this._rowRefs.push(ref);
};
// your render row function
renderRow = (data) => (
// make this row key consistent and unique like Id, do not use index counter as key
<PersonalRankItem key={data.id} dados={data} ref={this.collectRowRefs}/>
);
// When your hidden side button is clicked
onButtonClicked = (data) => {
// do the button normal action
// ....
// close each row
this._rowRefs.forEach((ref) => {
ref.closeRow();
});
};
// this is your hidden side button
renderLeftHiddenRow = () => (
<Button onClick={this.onButtonClicked} />
);
render() {
// Your List in here
return (
<List
renderRow={this.renderRow}
renderLeftHiddenRow={this.renderLeftHiddenRow}
/>
)
}
}

FlatListFooter can't be displayed

I want to add footer to my flatList :
i try this code :
renderFooter = () => {
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "#CED0CE"
}}
>
<Button> This is footer </Button>
</View>
);
}
<FlatList
data={menuData}
renderItem={({item}) => <DrawerItem navigation={this.props.navigation} screenName={item.screenName} icon={item.icon} name={item.name} key={item.key} />}
ListFooterComponent ={this.renderFooter}
/>
But no footer appears when running.
Any help please
You used the component
ListFooterComponent
in right way. you need to check your render method for footer. I faced the same issue and i follow this example, and it helps me. I hope it will help you.
Simple way/hack. In the menuData array, you just add a flag (i called) to the child object to indicate that it's a last item. For eg:
If you can modify your menuData structure, added lastItem prop true to indicate that it's the last item :
const menuData = [
{name:'menu1', screenName:'screen1', icon:'../assets/icon1.png'},
{name:'menu2', screenName:'screen2', icon:'../assets/icon2.png', lastItem:true}
];
and then
renderFlatItems = ({item}) => {
const itemView = null;
if (!items.lastItem) {
itemView = <DrawerItem navigation={this.props.navigation} screenName={item.screenName} icon={item.icon} name={item.name} key={item.key} />
} else {
itemView = <View style={{padding:100}}><Button> This is footer </Button> </View>
}
return {itemView};
}
then use it in the Flatlist like so
<FlatList
data={menuData}
renderItem={this.renderFlatItems}
/>
If you want a footer that remains at the bottom of the screen "Above" the list, then you can just add a View after the FlatList.
<View>
<FlatList style={{flex: 1}} />
<View
style={{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height: 50,
}}
/>
</View>