Trying to set different styles on two items from JSON - javascript

I try to build a news app that shows on the MainPage an overview of news items.
The first 3 items need to be rendered different as the rest, using a FlatList.
First item is a 100% background image with some text on it (did this with: if index === 0))
The second and third item needs to be background images with titles in a row (so next to each other)
The rests is a list with image, title, and date (underneath each other)
I tried everything but item 2 and 3 is not working.
Tried with this little basic test:
import React, { Component } from "react";
import { View, StyleSheet, Text, FlatList } from "react-native";
export default class Screen1 extends Component {
state = {
data: [
{
text: "one"
},
{
item1: {
text: "two"
},
item2: {
text: "three"
}
},
{
item1: {
text: "four"
},
item2: {
text: "five"
}
},
{
item1: {
text: "six"
}
}
]
};
renderItem = ({ item, index }) => {
if (index === 0) {
return (
<View style={styles.bigSquare}>
<Text> {item.text} </Text>{" "}
</View>
);
} else if (index > 0 || index <= 3) {
return (
<View
style={{
flexDirection: "row"
}}
>
{" "}
{item.item2 && (
<View
style={[
styles.smallSquare,
{
backgroundColor: "red"
}
]}
>
<Text> {item.item2.text} </Text> <Text> {item.item2.text} </Text>{" "}
</View>
)}{" "}
</View>
);
}
};
keyExtractor = (item, index) => `${index}`;
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
/>{" "}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
bigSquare: {
flexDirection: "column",
height: 220,
width: "100%",
margin: 10,
backgroundColor: "yellow",
justifyContent: "center",
alignItems: "center"
},
smallSquare: {
height: 100,
width: 100,
margin: 10,
backgroundColor: "green",
justifyContent: "center",
alignItems: "center"
}
});
Can someone point me in the right direction?
Example:

This approach is a little bit different. Separate your list into 3 parts which include,
First item
Second & third items
Rest of items (use FlatList to render this part)
Finally, you can display those 3 parts in different ways. But make sure to display part 1 & 2 as a ListHeaderComponent of FlatList.
import React, { Component } from "react";
import { SafeAreaView, View, FlatList, StyleSheet, Text, Dimensions } from "react-native";
const ScreenWidth = Dimensions.get('window').width;
const DATA = [
{
id: "1",
title: "First Item"
},
{
id: "2",
title: "Second Item"
},
{
id: "3",
title: "Third Item"
},
{
id: "4",
title: "Forth Item"
},
{
id: "5",
title: "Fifth Item"
},
{
id: "6",
title: "Sixth Item"
},
{
id: "7",
title: "Seventh Item"
}
];
export default class Example extends Component {
renderHeader = () => (
<View>
{/* Display index === 0 item */}
<View style={styles.bigSquare}>
<Text>{DATA[0].title}</Text>
</View>
{/* Display index > 0 && index < 3 items */}
<View style={{ flexDirection: 'row' }}>
<View style={styles.middleSqure}>
<Text>{DATA[1].title}</Text>
</View>
<View style={styles.middleSqure}>
<Text>{DATA[2].title}</Text>
</View>
</View>
</View>
)
renderItems = ({ item }) => (
<View style={styles.smallSquare}>
<Text>{item.title}</Text>
</View>
);
render() {
return (
<SafeAreaView style={{flex: 1, marginTop: 20}}>
{/* Display rest of item in a FlatList */}
<FlatList
data={DATA.slice(2)}
renderItem={this.renderItems}
ListHeaderComponent={this.renderHeader}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
bigSquare: {
height: 220,
width: ScreenWidth - 20,
margin: 10,
backgroundColor: "yellow",
justifyContent: "center",
alignItems: "center"
},
middleSqure: {
height: (ScreenWidth - 40) / 2,
width: (ScreenWidth - 40) / 2,
margin: 10,
backgroundColor: "red",
justifyContent: "center",
alignItems: "center"
},
smallSquare: {
height: 100,
width: 100,
margin: 10,
backgroundColor: "green",
justifyContent: "center",
alignItems: "center"
},
});
Hope this helps you. Feel free for doubts.

Related

FlatList Horizontal Scrolling

I'm creating onBoarding screens and I have created each of the screen item as a component and trying to render them with Flatlist so far everything is working smoothly but when I swipe the flatlist to see the other screens it's not working it swipes 40% and and forcefully shows the current screen it seems like there is some flex styling issues and I could able to figure it out please suggest.
Here is the video for explaination: https://youtube.com/shorts/pHbTs7ifMww
OnBoardingScreen.js
import React, { useState } from 'react';
import { Dimensions, FlatList, SafeAreaView, View, StyleSheet, Text, Image } from 'react-native';
const { width, height } = Dimensions.get('window');
const COLORS = {primary : '#ff006c', white: '#ffffff', black: '#000000'};
const slides = [
{
id: '1',
image: require('../../images/OnBoardingImages/1.png'),
title: 'You can mark time',
description: 'Lorem ipsum is a placeholder text commonly used to demonstrate the visual',
},
{
id: '2',
image: require('../../images/OnBoardingImages/2.png'),
title: 'You can mark time',
description: 'Lorem ipsum is a placeholder text commonly used to demonstrate the visual',
},
{
id: '3',
image: require('../../images/OnBoardingImages/3.png'),
title: 'You can mark time',
description: 'Lorem ipsum is a placeholder text commonly used to demonstrate the visual',
},
]
const Slide = ({item}) => {
return (
<View style={styles.slideView}>
<Image source={item.image} style={styles.slideImage} />
<Text style={styles.slideTitle}>{item.title}</Text>
<Text style={styles.slideDescription}>{item.description}</Text>
</View>
);
}
const OnBoardingScreen = ({ navigation }) => {
const [currentSlideIndex, setCurrentSlideIndex] = useState(0);
const Footer = () => {
return (
<View style={styles.footer}>
<View style={styles.pagination}>
{slides.map((_, index) => (<View key={index} style={[styles.paginationItem, currentSlideIndex == index && {backgroundColor: 'grey'} ]} /> ))}
</View>
</View>
);
};
return (
<SafeAreaView style={styles.root}>
<FlatList
data={slides}
contentContainerStyle={{flex: 1}}
showsHorizontalScrollIndicator={false}
horizontal
pagingEnabled
renderItem={({item}) => <Slide item={item} />} />
<Footer />
</SafeAreaView>
);
};
export default OnBoardingScreen;
const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: COLORS.white,
},
slideView: {
alignItems: 'center',
},
slideImage: {
height: '75%',
width: width,
resizeMode: 'contain',
},
slideTitle: {
color: COLORS.primary,
fontSize: '22',
fontWeight: 'bold',
marginVertical: 10,
paddingHorizontal: 10,
textAlign: 'center',
},
slideDescription: {
fontSize: 18,
paddingHorizontal: 20,
color: 'grey',
textAlign: 'center',
},
footer: {
height: height * 0.25,
paddingHorizontal: 20,
justifyContent: 'space-between',
},
pagination: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 20,
},
paginationItem: {
height: 10,
width: 10,
backgroundColor: COLORS.primary,
marginHorizontal: 3,
borderRadius: 50,
},
});
App.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import Navigation from './src/navigation';
export default function App() {
return (
<View style={styles.container}>
<Navigation />
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
Update this style
slideView: {
alignItems: 'center',
width: width
},

How to make spring animation on 'FlatList' item react native

I'm trying to make animation in flatlist, something like this, it will have spring animation when moving item
Something like apple music you can see: https://streamable.com/yg1j2j
With the help of #David Scholz, I was able to make exactly the same, here is expo for that:
https://snack.expo.dev/#quockhanh210199/animated-list-selection
But problem is, when i enable scroll it will have weird animation, so my question is, how to make the animation behavior correct if i enable scroll, you can see the weird animation if you enable scroll and and more item, or use below code:
import React, {useState, useCallback} from 'react';
import { StyleSheet, Text,View, SafeAreaView, ScrollView, StatusBar, Animated,FlatList,TouchableOpacity } from 'react-native';
const App = () => {
const data = [
{
id: "1",
text: "Results",
},
{
id: "2",
text: "Products",
},
{
id: "3",
text: "Stores",
},
{
id: "4",
text: "Stores",
},
{
id: "5",
text: "Stores",
},
{
id: "6",
text: "Stores",
},
]
const [translateValue] = useState(new Animated.Value(0))
const [selected, setSelected] = useState(0)
const onPress = React.useCallback(
(index) => {
setSelected(index)
Animated.spring(translateValue, {
toValue: index * 100,
velocity: 5,
useNativeDriver: true,
}).start()
},
[translateValue, setSelected]
)
return (
<View style={{ flexDirection: "row", marginTop: 100 }}>
<Animated.View
style={[
{
position: "absolute",
backgroundColor: "black",
top: -5,
right: 0,
bottom: 0,
left: 15,
width: 70,
height: 30,
borderRadius: 12,
transform: [{ translateX: translateValue }],
},
]}
/>
<FlatList
data={data}
horizontal={true}
scrollEnabled={true}
renderItem={({ item, index }) => {
return (
<TouchableOpacity onPress={() => onPress(index)}>
<View style={{ width: 100, borderRadius: 10 }}>
<Text style={[{ textAlign: "center" }, index === selected ? { color: "white" } : { color: "black" }]}>
{item.text}
</Text>
</View>
</TouchableOpacity>
)
}}
keyExtractor={(item) => item.id}
/>
</View>
)
}
export default App
Please help, thank you so much

Undefined is not an object evaluating title.length React Native

When I submit a form in React Native I get the below error undefined is not an object (evaluating 'title.length'). This problem occurs when I submit a form when the Card.js should be rendering the data from the form. I have checked and its getting the data back fine, seems to be a problem with rendering the data that its reading as undefined. After this error the form actually submits successfully and the Card.js displays the data.
Card.js
import React from "react";
import {
StyleSheet,
View,
Text,
ImageBackground,
TouchableOpacity,
} from "react-native";
const Card = (props) => {
const {
navigation,
title,
address,
homeType,
description,
image,
yearBuilt,
price,
id,
} = props;
return (
<TouchableOpacity
onPress={() => props.navigation.navigate("HomeDetail", { houseId: id })}
>
<View style={styles.card}>
<View style={styles.titleContainer}>
<Text style={styles.title}>
{title.length > 30 ? title.slice(0, 30) + "..." : title}
</Text>
</View>
<View style={styles.imageContainer}>
<ImageBackground source={{ uri: image }} style={styles.image}>
<Text style={styles.price}>${price}</Text>
<View style={styles.year}>
<Text style={styles.yearText}>{yearBuilt}</Text>
</View>
</ImageBackground>
</View>
<View style={styles.description}>
<Text style={styles.descriptionText}>
{description.length > 100
? description.slice(0, 100) + "..."
: description}
</Text>
</View>
</View>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
card: {
shadowColor: "black",
shadowOpacity: 0.25,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 8,
borderRadius: 10,
backgroundColor: "#ffffff",
elevation: 5,
height: 300,
margin: 10,
},
titleContainer: {
height: "15%",
padding: 10,
},
title: {
fontSize: 18,
fontWeight: "bold",
color: "gray",
},
imageContainer: {
width: "100%",
height: "65%",
overflow: "hidden",
},
image: {
width: "100%",
height: "100%",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "flex-end",
},
price: {
fontSize: 30,
color: "#fff",
margin: 10,
},
year: {
margin: 10,
backgroundColor: "#2652B0",
height: 25,
width: 80,
borderRadius: 5,
},
yearText: {
fontSize: 20,
color: "#fff",
textAlign: "center",
},
description: {
margin: 10,
},
descriptionText: {
fontSize: 16,
color: "gray",
},
});
export default Card;
HomeListScreen.js
import React, { useEffect, useState } from "react";
import {
StyleSheet,
View,
Text,
FlatList,
ActivityIndicator,
} from "react-native";
import { FloatingAction } from "react-native-floating-action";
import { useDispatch, useSelector } from "react-redux";
import Card from "../components/Card";
import * as houseAction from "../redux/actions/houseAction";
const HomeListScreen = (props) => {
const dispatch = useDispatch();
const [isLoading, setIsLoading] = useState(false);
const { houses } = useSelector((state) => state.house);
useEffect(() => {
setIsLoading(true);
dispatch(houseAction.fetchHouses())
.then(() => setIsLoading(false))
.catch(() => setIsLoading(false));
}, [dispatch]);
if (isLoading) {
return (
<View style={styles.centered}>
<ActivityIndicator size="large" />
</View>
);
}
if (houses.length === 0 && !isLoading) {
return (
<View style={styles.centered}>
<Text>No home found. You could add one!</Text>
</View>
);
}
return (
<View style={styles.container}>
<FlatList
data={houses}
keyExtractor={(item) => item._id}
renderItem={({ item }) => (
<Card
navigation={props.navigation}
title={item.title}
address={item.address}
homeType={item.homeType}
description={item.description}
price={item.price}
image={item.image}
yearBuilt={item.yearBuilt}
id={item._id}
/>
)}
/>
<FloatingAction
position="right"
animated={false}
showBackground={false}
onPressMain={() => props.navigation.navigate("AddHome")}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
centered: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
export default HomeListScreen;
<Text style={styles.title}>
{ title ? (title.length > 30 ? title.slice(0, 30) + "..." : title):true}
</Text>
Make sure that title is not undefined.

react-native , customer flatlist picker, returning previous values on selection

Below is the code component for the customer picker
import React, { useEffect, useState } from "react";
import { connect } from 'react-redux';
import {
TouchableOpacity,
FlatList,
SafeAreaView,
StatusBar,
StyleSheet,
Text,
View,
Button,
Alert,
} from "react-native";
import { screenHeight, screenWidth } from "../constants";
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "Client Not Found"
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Client refused"
},
];
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.item, style]}>
<Text style={styles.title}>{item.title}</Text>
</TouchableOpacity>
);
const StatusOptions = (props) => {
const [selectedId, setSelectedId] = useState(null);
const renderSeparator = () => (
<View
style={{
backgroundColor: "grey",
height: 0.8
}}
/>
);
const ListHeader = () => {
//View to set in Header
return (
<View style={{ height: 20 }}></View>
);
};
const renderItem = ({ item }) => {
const backgroundColor = item.id === selectedId ? "#6cd9ff" : "white";
return (
<Item
item={item}
onPress={() => {
setSelectedId(item.id);
console.log("SELECTED ID _ STATUSOPTIONS component : ", selectedId);
const val = DATA.filter(status => status.id == selectedId).map(filteredStatus => filteredStatus.title);
console.log("VALLLLLLLLLLLLLLLLLLLLLLLUUUUUUEEEEEEEEEEEEEEEEEEEE:::: ", val);
props.navigation.navigate('AnotherScreen');
}}
style={{ backgroundColor }}
/>
);
};
return (
<View style={{ bottom: 0, flex: 1, position: 'absolute', width: screenWidth, }}>
<View style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
ItemSeparatorComponent={renderSeparator}
ListHeaderComponent={ListHeader}
style={{
backgroundColor: "white",
width: "100%",
borderTopRightRadius: 20,
borderTopLeftRadius: 20,
zIndex: 1,
}}
/>
</View>
<View style={{ backgroundColor: "grey", height: 0.4 }} />
<View style={styles.closeButtonContainer}>
<TouchableOpacity style={styles.closeButton}
onPress={() => {
props.setStatusOptionsVisible(false)
}}>
<Text style={styles.title}>Close</Text>
</TouchableOpacity>
</View>
</View>
);
};
function mapStateToProps(state) {
return {
StatusOptionsVisible: state.volunteerItems.statusOptionsVisible,
currentTaskItemId: state.taskItems.taskItemId,
};
}
function mapDispatchToProps(dispatch) {
return {
setStatusOptionsVisible: (visible) => dispatch({ type: 'SET_STATUS_VISIBLE', statusVisibility: visible }),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(StatusOptions);
const styles = StyleSheet.create({
closeButton: {
backgroundColor: 'lightgrey',
borderRadius: 10,
height: 50,
justifyContent: 'center',
width: '90%',
},
closeButtonContainer: {
alignItems: 'center',
height: 90,
justifyContent: 'center',
backgroundColor: 'white',
},
textStyle: {
textAlign: "center",
},
container: {
borderRadius: 30,
flex: 4,
width: screenWidth,
},
item: {
padding: 20
},
title: {
fontSize: 20,
fontWeight: 'bold',
color: "black",
textAlign: "center"
}
});
the console Log : ("SELECTED ID _ STATUSOPTIONS component : ", selectedId)
in render Item function returns null for first picker item selection and the returns the previous value for the next picker item selection , can anyone please help with fixing it ?
Try to use this
useEffect(() => {
console.log("SELECTED ID _ STATUSOPTIONS component : ", selectedId);
if(selectedId != null) {
const val = DATA.filter(status => status.id == selectedId).map(filteredStatus => filteredStatus.title);
console.log("VALLUUEEEEEEEEEEEEEEEEEEEE:::: ", val);
}
}, [selectedId])

underline the clicked text element

I have a list of text elements that I want to underline when clicked. If I add the text decoration to the tabText then obviously it is applied to all items. How can I make sure that the when I click on another tab, the underline from the previous tab gets removed?
Is there any way I can add or remove items from the style element upon clicking on an item?
//onPress={() => {}}>
const tabs = [
{
id: 1,
text: 'Alle List',
},
{
id: 2,
text: 'Second',
},
];
export const Tab: React.FunctionComponent = () => {
return (
<View style={styles.tabView}>
{tabs.map((item: any) => (
<View>
<Text style={styles.tabText}>{item.text}</Text>
</View>
))}
</View>
);
};
const styles = StyleSheet.create({
tabView: {
paddingTop: moderateScale(15),
paddingLeft: moderateScale(20),
paddingRight: moderateScale(20),
flexDirection: 'row',
justifyContent: 'space-between',
},
tabText: {
color: 'white',
paddingBottom: moderateScale(10),
//textDecorationLine: 'underline'
},
});
Codesandbox (with tabText items as an array too):
https://snack.expo.io/#nhammad/shallow-watermelon
You can use useState to save the selected index and then apply another style based on the selected index. Here is a quick modification to your script and the snack link is at the end.
import * as React from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
const tabs = [
{
id: 1,
text: 'All Friends',
},
{
id: 2,
text: 'Second',
},
{
id: 3,
text: 'Third',
},
];
export default function App() {
const [selected, setSelected] = React.useState(null)
return (
<View style={styles.container}>
<View style={styles.tabView}>
{tabs.map((item: any, index) => (
<TouchableOpacity onPress={()=>setSelected(index)}>
<View>
<Text style={[styles.tabText,selected===index?styles.selected:null]}>{item.text}</Text>
</View>
</TouchableOpacity>
))}
</View>
</View>
);
}
const styles = StyleSheet.create({
tabView: {
paddingTop: 15,
paddingLeft: 20,
paddingRight: 20,
flexDirection: 'row',
justifyContent: 'space-between',
},
tabText: {
color: 'black',
paddingBottom: 10,
},
selected: {
textDecorationLine: 'underline'
},
});
https://snack.expo.io/#saachitech/da6280
You can add different styles for your tab depending on active route
<Text style={[(this.props.activeRouteName == route.routeName) ? styles.tabActiveText: styles.tabText]}>{item.text}</Text>
And then in the styles
tabActiveText: {
color: 'white',
paddingBottom: moderateScale(10),
textDecorationLine: 'underline'
}

Categories