I have already done firebase with user authentication. Each result is displayed in a flatlist. Upon clicking the heart icon I want to move the selected item to the favorite screen.
Home Screen
<FlatList
contentContainerStyle={ { alignSelf:"center",}}
data={Results}
keyExtractor={(Result) => Result.id.toString()}
renderItem={({ item }) => {
// console.log(item.id);
return (
<TouchableOpacity
onPress={() => {
navigation.navigate("ResultsShowScreen", {
id: item.id,
image: item.image,
});
}}
>
<ResultsDetail Result={item} />
</TouchableOpacity>
);
}}
/>
</View>
Favorites Screen
<View>
<Text> Screen</Text>
</View>
You can achieve this by reading the properties of the route.params object of your Favorite Screen. Like so:
function Favorites ({route}) {
const {id, image} = route.params;
return (
...
);
}
Keep in mind that this will only show the id and image you are passing when the TouchableOpacity is pressed. If you want a list of all the favorites, you need to store them on a data structure like an array (and modify the array when an item is faved/unfaved), and pass that array to the Favorite Screen
For the complete reference of this feature, you can read the Passing parameters to routes page of React Navigation docs.
Related
I'm making an app with some products that I got from my Wordpress database. On the homescreen, I have an overview of all the products, each in a tile. I want to be able to put a button in each tile, which links to the specific product page. But, since it works with a component, I need to be able to do this with a prop. And, if possible, based on the title of the API.
This is my code for the screen with all the products:
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, FlatList, Image, Button } from 'react-native';
import SuitcaseItem from '../components/SuitcaseItem';
const AllSuitcasesScreen = ({ navigation }) => {
const [suitcases, setSuitcases] = useState([]);
const getSuitcases = async () => {
try {
const response = await fetch("https://evivermeeren.com/wp-json/wp/v2/posts?categories=59", {
}
)
const json = await response.json();
console.log(json);
setSuitcases(json);
} catch (error) {
console.error(error);
}
}
useEffect(() => {
getSuitcases();
}, []);
return (
<View style={styles.screen}>
<View style={styles.flexbox2}>
<Text style={styles.products}>Onze koffers</Text>
<View style={styles.shoppingcart}>
<Image
style={styles.icon}
source={{uri: 'https://cdn-icons-png.flaticon.com/512/1413/1413908.png'}}
/>
<Text style={styles.number}>0</Text>
</View>
</View>
<View style={styles.list}>
<FlatList
data={suitcases}
renderItem={({ item }) => (
<SuitcaseItem
title={item.title.rendered}
imageUri={{uri: 'https://www.samsonite.be/on/demandware.static/-/Sites/default/dw851ab6f0/images/misc/sams_share-image.jpg'}}
desc={item.slug}
buttonText={item.title.rendered}
/>
)}
/>
</View>
</View>
);
}
export default AllSuitcasesScreen;
And this is the result:
Now, when I click the black button, I go to the page 'Evo L', which I also made. This is the button that I use:
<Pressable style={styles.seeProduct} onPress={() => navigation.navigate("Evo L")}>
<Text style={styles.text}>Bekijk product: {props.buttonText}</Text>
</Pressable>
This is in another file, the 'SuitcaseItem'.
So, I should be able to put something like navigation.navigate("props.buttonNav") with buttonNav = {item.title.rendered} so it goes to the page Evo L if I click on that one and then Evo M when I click on that tile and so one. Does anyone have an idea?
You can pass props to a screen. See this excellent official documentation for React Navigation on passing props.
-> Make a generic item detail screen like ItemDetail (instead of Evo L).
-> Modify the navigation.navigate("props.buttonNav") to:
navigation.navigate("ItemDetail", {itemTitle: props.buttonText})
You can access these props in the ItemDetail screen as:
function ItemDetail({ navigation, route }) {
return(
<Text>route.params.itemTitle</Text>
)
}
I want to be able to change the icon in a list of todos (see picture) from an exclamation mark, to a checkmark. That should happen if the user puts the finger on the icon, or the developer clicks with the mouse in the emulator.
Through the code below, I manage to change it, but the new icon only appears if I close the modal containing the list, and reopen it. So the modal does not re-render, neither partly nor in whole.
How can I make the changes appear live, immediately after I click the exclamation icon? I suspect it has to do with state, but it doesn't seem possible to create a React hook inside the map function. If I let onPress call a function, then the state is only known within that external function, and I don't know how to export it.
export const TeacherMessages = (props) => {
return (
<View
style={[
styles.borderBox,
props.todos.length > 0 || props.notes.length > 0
? styles.whiteBox
: null,
]}
>
{
props.todos.map((todo) => (
<View key={todo.id} style={styles.listNotes}>
<AntDesign
style={styles.listIcon}
onPress={() => todo.isChecked = true}
name={todo.isChecked ? "checksquare" : "exclamationcircle"}
color={todo.isChecked ? "green" : "red"}
size={18}
/>
<Text style={styles.listText}> {todo.description}</Text>
</View>
))
}
);
I think you need to store the todos array in a react hook so that way the changes you do to it becomes live instantly, You can have this changeTodo function in the parent component and pass it as props to call it from the child component with the index needed. I think this might help:
export const TeacherMessages = (props) => {
const [todosArr, setTodosArr] = React.useState(props.todos)
const checkTodo = (todoIndex) =>{
let arr = [...todosArr]
arr[todoIndex].isChecked= true
setTodosArr(arr)
}
return (
<View
style={[
styles.borderBox,
todosArr.length > 0 || props.notes.length > 0
? styles.whiteBox
: null,
]}
>
{
todosArr.map((todo, index) => (
<View key={todo.id} style={styles.listNotes}>
<AntDesign
style={styles.listIcon}
onPress={() => checkTodo(index)}
name={todo.isChecked ? "checksquare" : "exclamationcircle"}
color={todo.isChecked ? "green" : "red"}
size={18}
/>
<Text style={styles.listText}> {todo.description}</Text>
</View>
))
}
);
So I am pretty new in react native, I am trying to develop a quiz game, where users will be given Set of answers. I want to select change the color of the component when it is pressed by the user, kind of toggle it. So far I came up with useState solution, but unfortunately cannot figure out how to exclude the change of color, I guess I need to follow indexing or something, can anyone please make me understand the process with the solution.
export const QuizScreen = ({ navigation,route }) => {
const [quizArray, setQuizArray] = React.useState([])
const [rightAnswer, setRightAnswer]= React.useState(false)
const [selectBtn, setSelectBtn] = React.useState("#fff")
return(
<View>
{quizArray[qno].answer.map(r=>
<TouchableHighlight style={[styles.listItem, {backgroundColor:selectBtn}]}
onPress={()=>{
setRightAnswer(r.rightAnswer)
setSelectBtn("#DDDDDD") //so this changes logically all the component from the list
}}
activeOpacity={0.6} underlayColor="#DDDDDD"
>
<Text>{r.option}</Text>
</TouchableHighlight>
)}
</View>
I need to know how do i implement the background change for only one and kinda make it toggle everytime user select or deselect. Thank you
You were right about using an index for determining the clicked list item.
You can change the color by storing the index of the selected item using selectBtn state and then using that state set the backgroundColor accordingly.
Here is how you can do it:
export const QuizScreen = ({ navigation, route }) => {
const [quizArray, setQuizArray] = React.useState([]);
const [rightAnswer, setRightAnswer] = React.useState(false);
const [selectBtn, setSelectBtn] = React.useState(null);
return (
<View>
{quizArray[qno].answer.map((r, index) => (
<TouchableHighlight
style={[
styles.listItem,
{ backgroundColor: selectBtn === index ? '#dddddd' : '#fff' },
]}
onPress={() => {
setRightAnswer(r.rightAnswer);
setSelectBtn(index);
}}
activeOpacity={0.6}
underlayColor="#DDDDDD">
<Text>{r.option}</Text>
</TouchableHighlight>
))}
</View>
);
};
Here is the working example: Expo Snack
2
I am showing some Audio data in Flat-list. Flat-list, I am showing in main class, But, RenderItem calling in separate class. So, Once I tapped particular row item, I am playing audio file. But, I have to change pause to play image. But, When I tried to change it, All images are getting changes.
Bydefault, I am showing all cells images with pause icon.
Also Once user taps on play/pause in audio player, Then I have to change flatlist current playing item row images either play/pause.
I am showing audio player in bottom of the screen. Once user tap on flatlist pause icon, I am playing audio player in bottom of the screen.
I have tired but, All cells images getting changing.
Any suggestions?
Note: We have different UI for Audio player, So, I have created customized UI for player instead of default media component.
Main class.js
selectedAudio = (item, index) => {
if (isConnected) {
if (!isEmpty(audioURL)) {
// console.log('selected audio url is', audioURL);
SoundPlayer.playUrl(audioURL);
this.setState({
paused: false,
currentPosition: 0,
currentTime: 0,
audioSelectedIndex: index,
});
}
} else {
}
}
renderItem = ({ item, indexx }) => (
<Cell
item={item}
onSelected={this.selectedAudio}
index={indexx}
audioSelectedIndex={this.state.audioSelectedIndex}
/>
)
render() {
return (
<View some styles>
<FlatList
style={styles.faltList}
showsVerticalScrollIndicator
data={podcast}
extraData={this.state}
ItemSeparatorComponent={this.separator}
renderItem={this.renderItem}
/>
</View>
);
}
Cell.js
export default class Cell extends PureComponent {
render() {
const { item, indexx, audioSelectedIndex } = this.props;
return (
<View style={styles.flatListCell}>
<View style={styles.containerText}>
<Text style={styles.title}>
{item.title}
</Text>
</View>
</View>
<TouchableWithoutFeedback onPress={this.props.onSelected.bind(this, item)}>
<Image
style={styles.playPause}
source={audioSelectedIndex === indexx ? res.images.play : res.images.pause}
/>
</TouchableWithoutFeedback>
</ImageBackground>
</View>
);
}
}
The issue is that you are destructuring ({ item, indexx }), and renderItem doesn't pass indexx but index. Change indexx to index.
renderPodcastItem = ({ item, index }) => (
<Cell
item={item}
onSelected={this.selectedAudio}
index={index}
audioSelectedIndex={this.state.audioSelectedIndex}
/>
)
Second mistake, you are doing this const { item, indexx, audioSelectedIndex } = this.props; but you are not passing indexx but index to Cell. In Cell component change to.
const { item, index, audioSelectedIndex } = this.props;
Third mistake you are passing this.renderItem to renderItem but the function is undefined.
renderItem={this.renderPodcastItem}
DEMO
I'm having trouble keeping the data in my Flatlist after coming back from another page. My scenario is as follows:
User goes to homepage and scrolls through 20 items
User clicks their profile tab changing page using react-native-router-flux
User clicks the home tab taking them back to the list however the list re-renders and starts from the top.
How can I stop this re-rendering and fetching the same data again?
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteReuest gets my data from firebase in batches of 5 and sets data: []
data: [...this.state.data, ...results]
I've tried using the below but not sure if this is correct, when i navigate away and back the data re-renders. I want to keep the data so the page will be exactly the same as when it was left.
shouldComponentUpdate(nextProps, nextState) {
if (JSON.stringify(this.state.data) !== JSON.stringify(nextState.data)) {
return true;
}
return false;
}
My flatlist:
<View>
<FlatList
scrollsToTop={false}
ref={(ref) => { this.flatListRef = ref; }}
showsHorizontalScrollIndicator={false}
onScroll={this.handleScroll}
data={this.state.data}
keyExtractor={item => item.key}
ListFooterComponent={this.renderFooter()}
onRefresh={this.handleRefresh}
refreshing={this.state.newRefresh}
onEndReached={this.handleEndRefresh}
onEndReachedThreshold={0.05}
getItemLayout={this.getItemLayout}
renderItem={this.renderItem}
/>
{this.state.refreshAvailable ? this.renderRefreshButton() : null}
</View>
Thanks for any help!
Coded long back for the dumb project, maybe this can help you
The View: used onLayout Prop for getting the y-axis
<ScrollView
ref={(ref) => this.scrollTo = ref}
contentContainerStyle={{margin:5,}}
>
<Card onLayout={(event) => this._findHeight(event.nativeEvent.layout, 'personal')}>
<Personal review={true}/>
</Card>
</ScrollView>
The Function: stored the y-axis; here i have used realm db
_findHeight = (e, name) => {
const {x, y, width, height} = e;
this.realm.write(() => {
this.realm.create('yLocation',{names:name,yaxis:y}) :
});
}
The AutoScroll Method: here i have used scrollTo method from ScrollView you can use any method using their ref
_scrollTo = (y) => {
this.scrollTo.scrollTo({x:0,y:y,animated:true});
}
Note : Call _scrollTo method in componentDidMount