react navigation: navigate outside component | map function - arrays

Hello I'm new to RN and I have little problem with my react navigation. I would like to write boxes from an array. Every box has same navigation path. I guess it's problem with navigating outside component but I have no idea how to fix it.
CODE:
WriteTeams() {
return teams_array.map(function(Teams, i){
return(
<View key={i}>
<TouchableHighlight onPress={() =>
this.props.navigation.navigate('TeamDetail')}>
<Text>{Teams.TeamName}</Text>
</TouchableHighlight>
</View>
);
});
}
render(){
<ScrollView>
<View>
<View>
{this.WriteTeams()}
</View>
</View>
</ScrollView>
}
}
const teams_array = [
{ TeamName: "Some team"},
{ TeamName: "Some team2"}
]
Error screen
Thanks for every answer.

The error message indicates that the navigation object is not being passed into the component as a property.
You will need to pass the navigation object from the render function to the WriteTeams component to make it available in your code.
I have copied and amended your code to help explain
WriteTeams(navigation) {
return teams_array.map(function(Teams, i){
return(
<View key={i}>
<TouchableHighlight
onPress={() => navigation.navigate('TeamDetail')}
>
<Text>{Teams.TeamName}</Text>
</TouchableHighlight>
</View>
);
});
}
render(){
return (
<ScrollView>
<View>
<View>
{this.WriteTeams(this.props.navigation)}
</View>
</View>
</ScrollView>
)
}
const teams_array = [
{ TeamName: "Some team" },
{ TeamName: "Some team2" }
]

Related

Navigation from menu item

I'm trying to get a menu item to navigate to another page but for some reason it wont let me do it. I'm a little confused as to how you go about it and any help is welcome!
Import here:
import { NavigationScreenProp } from "react-navigation";
Here is more code:
interface NotificationDropdownProps {
navigation: NavigationScreenProp<any, any>;
}
Here is where function is called:
function renderNotification(notification: INotification) {
return (
<MenuOption
onSelect={() => {
if (notification.type == INotificationType.SYSTEM) {
this.testFunction();
}
}}
>
<View style={[styles.notificationContainer]}>
<View style={styles.iconArea}>
<View style={[styles.iconCircle]}>
<Icon
name={this.getIconType(notification.type)}
color={this.notificationColor(notification.type)}
size={26}
/>
</View>
</View>
<View>
<Text>{notification.text}</Text>
<Text>
{this.getDate(new Date(notification.dateCreated))}
</Text>
</View>
</View>
</MenuOption>
);
}
Test Function:
testFunction(){
this.props.navigation.navigate('NextPage')
};
Error:
undefined is not an object(evaluating'_this2.props.naviagtion.navigate)
Where the function is called:
<View>
<Text>
Notifications
</Text>
{this.props.notifications.length > 0 ? (
<FlatList
contentContainerStyle={{ borderRadius: 10 }}
data={this.props.notifications.slice(0, 5)}
renderItem={({ item }) => this.renderNotification(item)}
keyExtractor={this.keyExtractor}
/>
) : (
<Text>No Notifications!</Text>
)}
</View>;
try with an arrow function to avoid using the context of the function.
testFunction = () => {
this.props.navigation.navigate('NextPage')
};

How to get object ID onPress and pass that value on to a new screen in React Native?

I've build an React Native app which shows a list of different objects on the ListScreen. I now want to with onPress show one object values on the ViewScreen
I've build my app using React-Redux and React-navigation now I'm not sure if I should store the data of the object in the store, but I'm not sure if that's the right way to use the Redux store (because I currently use it for the cart items) or If there is another way to pass on these value's on to the ViewScreen.
This is a simplification of my app:
I've made a static Data.js file to test app
Data.JS
`id: 0,
name: 'John Doe',
age: '15',
gender: 'male',
`
Then I import the data into the ListScreen
List.js
`import { object} from './Data';
state = {
object,
};
renderRow = (rowData) => {
return (
<View>
<TouchableOpacity onPress={() => this.props.id.navigation.navigate('ViewScreen')}>
<View>
<Text>
{rowData.item.name}
</Text>
</View>
</TouchableOpacity>
</View>
)
}
render() {
return (
<View>
<FlatList
renderItem={this.renderRow}
keyExtractor={(item, index) => index.toString()}
/>
</View>
)
}
`
ViewScreen
` state = {
object,
};
renderRow = (rowData) => {
return (
<View>
<TouchableOpacity onPress={() => this.props.id.navigation.navigate('ViewScreen')}>
<View>
<Text>
{rowData.item.name}
{rowData.item.age}
{rowData.item.gender}
</Text>
</View>
</TouchableOpacity>
</View>
)
}
render() {
return (
<View>
<FlatList
renderItem={this.renderRow}
keyExtractor={(item, index) => index.toString()}
/>
</View>
)
}
`
How do I pick it up from here? So that the value's get shown in the ViewScreen
you are almost there just add this second argument to your on press method and it's done.
You will get this data in data prop of next screen.
renderRow = (rowData) => {
return (
<View>
<TouchableOpacity onPress={() =>
this.props.id.navigation.navigate('ViewScreen',{data : rowData})}>
<View>
<Text>
{rowData.item.name}
{rowData.item.age}
{rowData.item.gender}
</Text>
</View>
</TouchableOpacity>
</View>
)
}

Adding item click event in react native Grid View

Please find my code below and help me for adding item click listener for the items in the grid view. Please find the link which I followed library link.
And I need to display the name in an alert when the user clicks on each item in the gridlist. Styles are not included in the code
Thanks in Advance
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TouchableWithoutFeedback
} from 'react-native';
import GridLayout from 'react-native-layout-grid';
class HomeScreen extends Component {
renderGridItem = (props) => (
<View style={styles.item} >
<View style={styles.flex} />
<Text style={styles.name} >
{props.name}
</Text>
</View>
);
render() {
const items = [];
for (let x = 1; x <= 30; x++) {
items.push({
name: `Grid ${x}`
});
}
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Grid Layout
</Text>
<View style={styles.flex}>
<GridLayout
items={items}
itemsPerRow={2}
renderItem={this.renderGridItem}>
</GridLayout>
</View>
</View>
);
}
}
export default HomeScreen;
Instead of using <View> in your renderGridItem, you could use one of the touchables component (react native doc).
For example with <TouchableOpacity >:
renderGridItem = (props) => (
<TouchableOpacity style={styles.item} onPress={() => this.showAlert(props.name)}>
<View style={styles.flex} />
<Text style={styles.name} >
{props.name}
</Text>
</TouchableOpacity>
);
showAlert = (name) => {
Alert.alert(
'Alert Title',
`The user name is: ${name}`,
[
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ cancelable: false }
)
}
Why don't you wrap renderGridItem in a TouchableWithoutFeedback?
renderGridItem = (props) => (
<TouchableWithoutFeedback onPress={()=> Alert.alert(props.name)}>
<View style={styles.item} >
<View style={styles.flex} />
<Text style={styles.name} >
{props.name}
</Text>
</View>
<TouchableWithoutFeedback />
);
Also you will need to import Alert from react-native.

React Native FlatList only responds to touches sometimes

I have used FlatList in multiple places in my app previously without any issues, but now when I created a new one it doesn't seem to register touches/swipes correctly. Only like 1/6 touches seem to register.
See the video here: https://photos.app.goo.gl/NZCtVYX6GLVCQN392
This is how I use the FlatList:
render() {
return (
<Container>
...
<FlatList
data={this.state.exercises}
renderItem={({item}) =>
<SetsRepsAndWeightItem exercise={item}/>
}
keyExtractor={item => item.name}
style={style.list}
/>
</Container>
);
}
And the SetsRepsAndWeightItem:
render() {
return (
<View style={style.container}>
<View style={style.header}>
<Text style={style.headerText}>{this.props.exercise.name}</Text>
</View>
<View style={style.about}>
<TouchableWithoutFeedback onPress={this.handleSetsPressed}>
<StatisticNumber metric="Sets" value={7}/>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={this.handleRepsPressed}>
<StatisticNumber metric="Reps" value={5}/>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={this.handleWeightPressed}>
<StatisticNumber metric="kg" value={35}/>
</TouchableWithoutFeedback>
</View>
</View>
);
}
handleSetsPressed = () => {
console.log("sets pressed");
}
handleRepsPressed = () => {
console.log("reps pressed");
}
handleWeightPressed = () => {
console.log("weight pressed");
}
Also: the TouchableWithoutFeedback elements are not calling their onPress functions when they are touched.
The Container is as simple as this:
export default class Container extends Component {
static propTypes = {
children: Proptypes.any,
backgroundColor: Proptypes.string
};
render() {
const containerStyles = StyleSheet.flatten([
style.container,
this.props.backgroundColor ? { backgroundColor: this.props.backgroundColor } : null,
]);
return (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<View style={containerStyles}>
{this.props.children}
</View>
</TouchableWithoutFeedback>
);
}
}
The following two fixes solved the issues for me:
Remove the onPress={() => Keyboard.dismiss()} from the Container component
Move the TouchableWithoutFeedback into the StatisticNumber component, and pass onPress as a prop from SetsRepsAndWeightItem

React Native: building a layout from data in an array

So I have a layout on screen which duplicates itself multiple times. I really want to clean it up. Currently it's like this:
import { content } from '../content.js';
class Display extends Component {
render() {
return (
<View style={styles.displayContainer}>
<ScrollView>
<View style={styles.row}>
<View style={styles.displayItemBlock}>
<TouchableOpacity style={styles.displayItem} onPress={this.item1}>
<Image
style={styles.displayItemImage}
source={require('../images/display-item1.jpg')}
/>
<View style={styles.displayItemText}>
<Text style={styles.displayItemTitle}>{content.display_title_item1}</Text>
<Text style={styles.recipeItemTime}>
<IconMCI name="clock" color="#4F8EF7" /> 2h 30m
</Text>
</View>
</TouchableOpacity>
</View>
<View style={styles.displayItemBlock}>
<TouchableOpacity style={styles.displayItem} onPress={this.item2}>
<Image
style={styles.displayItemImage}
source={require('../images/display-item2.jpg')}
/>
<View style={styles.displayItemText}>
<Text style={styles.displayItemTitle}>{content.display_title_item2}</Text>
<Text style={styles.recipeItemTime}>
<IconMCI name="clock" color="#4F8EF7" /> 45m
</Text>
</View>
</TouchableOpacity>
</View>
{/* AND REPEAT... */}
</View>
</ScrollView>
</View>
);
}
}
So I thought I could easily replace most of this with a map which will take the information which changes and put that into an array. So now I have this:
import { content } from '../content.js';
const dataArray = [
{ img: '../images/display-item1.jpg',
title: 'content.display_title_item1',
func: 'item1',
time: '2h 30m' },
{ img: '../images/display-item2.jpg',
title: 'content.display_title_item2',
func: 'item2',
time: '45m' },
];
class Display extends Component {
ShowEverything() {
return dataArray.map(function (data, i) {
return (
<View key={i} style={styles.displayItemBlock}>
<TouchableOpacity style={styles.displayItem} onPress={this.{data.func}}>
<Image
style={styles.displayItemImage}
source={require({data.img)}
/>
<View style={styles.displayItemText}>
<Text style={styles.displaytemTitle}>{data.title}</Text>
<Text style={styles.displayItemTime}>
<IconMCI name="clock" color="#4F8EF7" /> {data.time}
</Text>
</View>
</TouchableOpacity>
</View>
);
});
}
render() {
return (
<View style={styles.displayContainer}>
<ScrollView>
<View style={styles.row}>
{this.ShowEverything()}
</View>
</Scroll>
</View>
);
}
}
What could be easier, right? :)
This, of course, doesn't work. The time (data.time) is output correctly, but the title doesn't pull the correct text from content.js (it just outputs the string content.display_title_item from the array). The img and func items also don't work as I would have expected.
Am I way off here? It seems like this is the most obvious way of keeping this DRY; any help would be appreciated.
Try this
import { content } from '../content.js';
const dataArray = [
{ img: require('../images/display-item1.jpg'), //this is a known issue in react, dynamic paths needs to assigned like this
title: 'display_title_item1',
func: 'item1',
time: '2h 30m' },
{ img: require('../images/display-item2.jpg'),
title: 'display_title_item2',
func: 'item2',
time: '45m' },
];
class Display extends Component {
ShowEverything() {
return dataArray.map((data, i) => { // changed to fat arrow func to be in scope of this
return (
<View key={i} style={styles.displayItemBlock}>
<TouchableOpacity style={styles.displayItem} onPress={this[data.func]}> // syntax error
<Image
style={styles.displayItemImage}
source={data.img}
/>
<View style={styles.displayItemText}>
<Text style={styles.displaytemTitle}>content[data.title]</Text> // syntax error
<Text style={styles.displayItemTime}>
<IconMCI name="clock" color="#4F8EF7" /> {data.time}
</Text>
</View>
</TouchableOpacity>
</View>
);
});
}

Resources