How to navigate between different components based on conditions in react native - javascript

I am building a a mobile app in react native in which I have videos and audios coming in same data array. Now I am rendering them into a flatlist and audios and videos are coming together randomly. Now I want that If I click on the audio file it should navigate to Audios component and if I click on any video it should navigate to Videos Component. But I don't know how to filter and navigate to their respective components. Kindly help me. Thank you
My code
Main File: It is navigating to Audio component either I click on audio file or either on video file
<FlatList
horizontal
data={latestuploads}
keyExtractor={item => item.id}
renderItem={({item}) => {
return (
<ScrollView horizontal={true}>
<Card transparent style={{width: 170}}>
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate('Audio', {id: item.id})
}>
<CardItem>
<ImageBackground
source={{uri: item.image_url}}
style={styles.image}>
<Image
source={require('../assets/play-icon.png')}
style={styles.icon}
/>
</ImageBackground>
</CardItem>
</TouchableOpacity>
<CardItem cardBody>
<Text numberOfLines={1} style={styles.title}>
{item.title}
</Text>
</CardItem>
<CardItem cardBody>
<Text style={styles.speaker}> {item.speaker} </Text>
</CardItem>
</Card>
</ScrollView>
);
}}
/>

I suppose you're getting file extension example .mp4/.mp3 etc or Audio/Video flag from your data array.
Create a function that takes file info example:
navigateTo = (fileinfo) => {
// const filetype = check for file type, Audio/Video or file extension
if (filetype === 'Audio'){
this.props.navigation.navigate('Audio', {id: fileinfo.id})
} else {
this.props.navigation.navigate('Video', {id: fileinfo.id})
}
Pass this to your TouchableOpacity:
<TouchableOpacity
onPress={() => navigateTo(item)}>
// your code here
</TouchableOpacity>

constructor()
{
super(props)
this.state = {
ItemindexChecked: "",
}
this.Dataarrayholder = latestuploads;
}
............................your code ............
DataFilter(p_value)
{
const newData = this.Dataarrayholder.filter(function (item) {
const itemData = item.value ? item.value.toUpperCase() : ''.toUpperCase();
const textData = p_value.toUpperCase();
return itemData.indexOf(textData) > -1;
if (p_value != "")
{
if (newData == 0) {
return
}
else
{
this.props.navigation.navigate('Audio', { id: newData[0].id });
}
}
});
}
...........................................your code ..............
<FlatList
horizontal
data={latestuploads}
keyExtractor={item => item.id}
renderItem={({ item }) => {
return (
<ScrollView horizontal={true}>
<Card transparent style={{ width: 170 }}>
<TouchableOpacity
//onPress={() =>
// // this.props.navigation.navigate('Audio', { id: item.id })
// }
onPress={() => { this.DataFilter(item.value), this.setState({ ItemindexChecked: item.key }) }}
>
<CardItem>
<ImageBackground
source={{ uri: item.image_url }}
style={styles.image}>
<Image
source={require('../assets/play-icon.png')}
style={styles.icon}
/>
</ImageBackground>
</CardItem>
</TouchableOpacity>
<CardItem cardBody>
<Text numberOfLines={1} style={styles.title}>
{item.title}
</Text>
</CardItem>
<CardItem cardBody>
<Text style={styles.speaker}> {item.speaker} </Text>
</CardItem>
</Card>
</ScrollView>
);
}}
/>
maybe it helpful for you

Related

React native : Flatlist inside scrollview

My goal is for this entire block to be scrollable.
I tried all kinds of ways to achieve the goal but without success.
I tried with ListHeaderComponent and moved the entire top view to it and it didn't work.
And I also tried <FlatList nestedScrollEnabled />
And it didn't work either.
What is the correct way to reach the scroll?
I come from here :
const renderAccordians = () => {
const items: JSX.Element[] = [];
areaData.forEach(item => {
items.push(<Accordian item={item} key={item.title} />);
});
return items;
};
To here :
return (
<View>
<View style={styles.row}>
<TouchableOpacity onPress={() => onClickFather()}>
<MaterialIcons size={24} name={data.checked ? 'check-box' : 'check-box-outline-blank'} color={'black'} />
</TouchableOpacity>
<Text style={[styles.title]}>{data.title}</Text>
<TouchableOpacity style={styles.row} onPress={() => toggleExpand()}>
<MaterialIcons name={expanded ? 'arrow-drop-up' : 'arrow-drop-down'} size={30} color={'black'} />
</TouchableOpacity>
</View>
<View style={styles.parentHr} />
{expanded && (
<FlatList
data={data.data}
numColumns={1}
scrollEnabled={false}
renderItem={({ item, index }) => (
<View>
<TouchableOpacity style={[styles.childRow, styles.button]} onPress={() => onClick(index)}>
<MaterialIcons
size={24}
name={item.checked ? 'check-box' : 'check-box-outline-blank'}
color={'black'}
/>
<Text style={[styles.itemInActive]}>{item.key}</Text>
</TouchableOpacity>
<View style={styles.childHr} />
</View>
)}
/>
)}
</View>
);
Since your FlatList will be part of an Accordion component, you "can't" embed the ExpandButton inside the Flatlist > ListHeaderComponent ... cause It'll simply hide the whole FlatList along with it's Header when you collapse your accorddion...
keyExtractor is also missing in your FlatList .. I added index as a key here which is not recommended BTW, you better use a unique field in your listItem like id...
return (
<View style={{ flex: 1}}> // <<--- Look here
<View style={styles.row}>
<TouchableOpacity onPress={() => onClickFather()}>
<MaterialIcons
size={24}
name={data.checked ? 'check-box' : 'check-box-outline-blank'}
color={'black'}
/>
</TouchableOpacity>
<Text style={[styles.title]}>{data.title}</Text>
<TouchableOpacity style={styles.row} onPress={() => toggleExpand()}>
<MaterialIcons
name={expanded ? 'arrow-drop-up' : 'arrow-drop-down'}
size={30}
color={'black'}
/>
</TouchableOpacity>
</View>
<View style={styles.parentHr} />
{expanded && (
<FlatList
data={data.data}
numColumns={1}
scrollEnabled={true} // <<--- Look here
keyExtractor={(_, index) => index.toString()} // <<=== Look here
contentContainerStyle={{flexGrow: 1}} // <<--- Look here
renderItem={({ item, index }) => (
<View>
<TouchableOpacity
style={[styles.childRow, styles.button]}
onPress={() => onClick(index)}
>
<MaterialIcons
size={24}
name={item.checked ? 'check-box' : 'check-box-outline-blank'}
color={'black'}
/>
<Text style={[styles.itemInActive]}>{item.key}</Text>
</TouchableOpacity>
<View style={styles.childHr} />
</View>
)}
/>
)}
</View>
);
If it does not work, I think you should create a component and use map datalist to render all the items and putting them into the ScrollView tag.
<ScrollView
style={styles.messageContain}
ref={ref => {
this.scrollView = ref;
}}
{data.data.map((item, index) => {
return <YourComponent key={index} data={item} />;
})}
</ScrollView>

localStorage doesn't work in TouchableOpacity tag

I want to use localStorage and move to another page at the same time, but only moving work, I can't get the value
const pressHandlerMapTest = () => {
navigation.navigate("TestMapScreen");
};
return (
<ImageBackground style={styles.background}>
<View style={styles.tourWindow}>
<TouchableOpacity underlayColor="red"
onPress={pressHandlerMapTest}
onPressIn={() => {
localStorage.setItem('tour', 'others');
}}>
<Image source={require("../assets/royals.png")} ></Image>
</TouchableOpacity>
</View>
</ImageBackground>
);
const pressHandlerMapTest = () => {
localStorage.setItem('tour', 'others');
navigation.navigate("TestMapScreen");
};
return (
<ImageBackground style={styles.background}>
<View style={styles.tourWindow}>
<TouchableOpacity underlayColor="red"
onPress={pressHandlerMapTest}
>
<Image source={require("../assets/royals.png")} ></Image>
</TouchableOpacity>
</View>
</ImageBackground>
);

React-native adding components to array and accessing them

I'm trying to make some sort of quiz, and I want to have all the boxes in a FlatList. I want all of them to be hidden, except for the first one, and that when you answer it the next question appears.
Here is my code:
const TYPE = [{id:"1",title:"first question",options:["option 1","option 2"],correct:1},{id:"2",title:"secondquestion",options:["option 1","option 2"],correct:0}];
const answer=a=>Alert.alert(a == 0 ? 'wrong' : 'correct');
const Item = ({info}) => (
<View style={styles.item}>
<Text style={styles.title}>
{info.title}
</Text>
<TouchableOpacity style={styles.button} onPress={() => info.correct == 0 ? answer(1) : answer(0)}>
<Text>
{info.options[0]}
</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={() => info.correct == 1 ? answer(1) : answer(0)}>
<Text>
{info.options[1]}
</Text>
</TouchableOpacity>
</View>
);
function HomeScreen({ navigation }) {
return (
<View style={styles.homescreen}>
<Text style={styles.homeTitle}>
Welkom!
</Text>
<Text style={styles.homeIntro}>
Play the test, yes?
</Text>
<TouchableOpacity style={styles.homeButton} onPress={() => navigate(navigation, "Type")}>
<Text style={styles.homeButtonText}>
Start the Test!
</Text>
</TouchableOpacity>
</View>
)
}
function type() {
const renderItem = ({ item }) => <Item info={item} />;
return (
<View style={styles.container}>
<FlatList
data={TYPE}
renderItem={renderItem}
keyExtractor={item => item.id}
style={styles.list}
/>
<StatusBar style="auto" />
</View>
);
}
export default function App() {
console.log("Starting...");
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Type" component={type} />
</Stack.Navigator>
</NavigationContainer>
)
}
My approach to this would be to add all s into an array, so that I can simply do this: itemArray[i].style.display='None' or something like that.
Try below code that could help to achieve what you want:
import React from 'react';
import {
Alert,
StatusBar,
Text,
TouchableOpacity,
View,
} from 'react-native';
const TYPE = [
{
id: '1',
title: 'first question',
options: ['option 1', 'option 2'],
correct: 1,
},
{
id: '2',
title: 'secondquestion',
options: ['option 1', 'option 2'],
correct: 0,
},
];
const Item = ({info, onPressOption}) => (
<View style={styles.item}>
<Text style={styles.title}>{info.title}</Text>
<TouchableOpacity style={styles.button} onPress={() => onPressOption(0)}>
<Text>{info.options[0]}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={() => onPressOption(1)}>
<Text>{info.options[1]}</Text>
</TouchableOpacity>
</View>
);
function HomeScreen({navigation}) {
return (
<View style={styles.homescreen}>
<Text style={styles.homeTitle}>Welkom!</Text>
<Text style={styles.homeIntro}>Play the test, yes?</Text>
<TouchableOpacity
style={styles.homeButton}
onPress={() => navigate(navigation, 'Type')}>
<Text style={styles.homeButtonText}>Start the Test!</Text>
</TouchableOpacity>
</View>
);
}
function QuestionScreen({navigation}) {
const [activeQuestionIndex, setActiveQuestionIndex] = React.useState(0);
const showAlert = (isCorrect, onPress) => {
Alert.alert(isCorrect ? 'correct' : 'wrong', null, [
{
onPress,
},
]);
};
const onPressOption = (optionIndex) => {
const isCorrectOption = TYPE[activeQuestionIndex].correct === optionIndex;
showAlert(isCorrectOption, () => {
isCorrectOption && setActiveQuestionIndex(activeQuestionIndex + 1);
});
};
return (
<View style={styles.container}>
<StatusBar style="auto" />
<Item info={TYPE[activeQuestionIndex]} onPressOption={onPressOption} />
</View>
);
}

How to use react native navigation to navigate from a FlatList component to a expanded component

I am creating a basic blog application using ReactNative. The home screen renders a FlatList of posts with a title, key, and author. I want to be able to click on an individual post and navigate to a new screen that has the full blog post. I will try and give as much code as possible to explain my problem.
// ./Post
function Post(props) {
const navigation = useNavigation();
return (
<TouchableOpacity
style={styles.container}
onPress={() =>
navigation.navigate({ name: "ExpandedPost", params: props.id })
}
>
<View>
<Text style={styles.post}>This is the title to a fake post</Text>
<Text style={styles.text}>By {props.Author} </Text>
</View>
<Image
source={{ uri: "https://picsum.photos/200/300" }}
style={styles.thumbnail}
/>
</TouchableOpacity>
);
}
// ./ExpandedPost
export default function ExpandedPost({ navigation, route }) {
return (
<View style={styles.container}>
<View>
<Text style={styles.post}>This is the title to a fake post</Text>
<Text> This is a body of a fake post</Text>
</View>
<Image
source={{ uri: "https://picsum.photos/200/300" }}
style={styles.thumbnail}
/>
</View>
);
}
// ./PostList
const RenderPosts = () => {
return (
<FlatList
data={fakePosts}
renderItem={({ item }) => <Post Author={item.Author} />}
/>
);
};
export default function PostList() {
return (
<View style={styles.container}>
<Header />
<RenderPosts />
</View>
);
}
Basically, I want to take the post that is rendered in PostList, and onPress I want to navigate to ExpandedPost that contains all of the data from the specific post.
This might help
// ./Post
function Post(props) {
const navigation = useNavigation();
return (
<TouchableOpacity
style={styles.container}
onPress={() =>
navigation.navigate("ExpandedPost", {item: props.item})
}
>
<View>
<Text style={styles.post}>This is the title to a fake post</Text>
<Text style={styles.text}>By {props.item.Author} </Text> <-- Change here -->
</View>
...
</TouchableOpacity>
);
}
// ./ExpandedPost
export default function ExpandedPost(props) {
const completeItemOfPost = props.item; <-- Complete Item Here -->
return (
<View style={styles.container}>
<View>
<Text style={styles.post}>This is the title to a fake post</Text> <-- You can show title like "completeItemOfPost.title" -->
<Text> This is a body of a fake post</Text> <-- You can show body like "completeItemOfPost.body" -->
</View>
<Image
source={{ uri: "https://picsum.photos/200/300" }} <-- You can show image like "completeItemOfPost.image" -->
style={styles.thumbnail}
/>
</View>
);
}
// ./PostList
const RenderPosts = () => {
return (
<FlatList
data={fakePosts}
renderItem={({ item }) => <Post item={item} />} <-- Pass complete item here... -->
/>
);
};}

ReactNative : Function called twice automatically inside FlatList

I have been in trouble seeking a solution to the silly problem. There is something missing from my code which I am unable to understand for now. Looking forward to your answers and information regarding the below code:
Constructor:
constructor(props) {
super(props)
this.TotalQuery = this.TotalQuery.bind(this);
this.state = {
isLoading: true,
Query: [],
}
this.UserID();
}
Function()
TotalQuery(product_id){
fetch(`http://:3000/api/v1/users/queries/${product_id}`, {
method: 'GET',
}).then((response) => response.json()).then((resp => {
this.setState({
Query: resp
})
})) .catch((error)=>{
console.log("Api call error1");
})
}
Calling this inside the Flatlist like below:
<FlatList
data={this.state.UserProducts}
keyExtractor={(item, index) => index.toString()}
renderItem= { ({item}) => (
<View style={styles.order}>
<View style={styles.orderHeader}>
<View style={styles.ohInfo}>
<Text style={styles.ohLabel}>Ref#</Text>
<Text style={styles.ohValue}>#2019-{item.product_id}</Text>
</View>
<View style={[styles.ohInfo, { backgroundColor: '#E7E7E7' }]}>
<Text style={styles.ohLabel}>Amount</Text>
<Text style={styles.ohValue}>€{item.price}</Text>
</View>
<View style={styles.ohInfo}>
<Text style={styles.ohLabel}>Messages</Text>
{this.TotalQuery(item.product_id)}
{this.state.Query.map((i, index) => (
<Text style={styles.ohValue}>{i.total}</Text>))}
</View>
</View>
<View style={styles.profileImgContainer}>
<View>
<ImageBackground style={styles.profileImgContainer}>
<Image source={{ uri: item.url }} style={[styles.profileImg]} />
</ImageBackground>
</View>
</View>
<View style={styles.orderBottom}>
<View style={styles.orderBottomLf}>
<Image resizeMode={'contain'} style={{ width: 14, height: 14 }}
source={require('../../assets/images/icon-pending-black.png')} />
<Text
style={[styles.orderStatusText]}>
{(item.status === 1) ? <Text style={styles.Approved}>Approved</Text> : null}
{(item.status === 2) ? <Text style={styles.Sold}>Sold</Text> : null}
{(item.status === 3) ? <Text style={styles.UnderReview}>Under Review</Text> : null}
{(item.status === 4) ? <Text style={styles.Inactive}>Inactive</Text> : null}
{(item.status === 5) ? <Text style={styles.Deleted}>Deleted</Text> : null}
</Text>
</View>
<View style={styles.orderBottomRg}>
<TouchableOpacity style={styles.profileImgContainer1} onPress={() => this.Sold(item.product_id)}>
{(item.status === 1) ? <Image style={[styles.profileImg1]} source={require('../../assets/images/checked.png')}/> : null}
</TouchableOpacity>
</View>
<View style={styles.orderBottomRg}>
<TouchableOpacity style={styles.profileImgContainer2} onPress={() => {this.Delete(item.product_id)}}>
{(item.status === 1 || item.status === 3 || item.status === 4) ? <Image style={[styles.profileImg2]} source={require('../../assets/images/delete.png')}/> : null }
</TouchableOpacity>
</View>
</View>
</View>
)}
/>
Above is the flatlist rendering, everything is rendering from it only. Please check.
There are multiple problems with your code.
The problem is that you are calling a function within the Flatlist renderItem method.
The way Flatlist works is you give it a data set and then it will call renderItem for each entry in that data set.
And then, any time your component re renders or the child item re renders the Flatlist will do this again.
Plus, it looks like you want to call this.TotalQuery(item.product_id) for each item in your data set but you are saving the return value to a single state value, so each call with overwrite the previous.
I would recommend moving your renderItem code into its own Component, and then each Component instance can have it's own state object where you can save the return value from your function call.

Categories

Resources