I work with the 'react-native-super-grid' library and I trying to figure out how to do the following 2 situations:
Displays a different icon for each item in the grid
for example : the PinIcon will be for the 'qq' and the CatIcon will be for the 'ww'.
How to make the items clickable with 'pressable' or 'TouchableOpacity'
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { createStackNavigator } from '#react-navigation/stack';
import { FlatGrid } from 'react-native-super-grid';
import PinIcon from '../src/assets/PinIcon.svg';
import CatIcon from '../src/assets/CatIcon.svg';
const HomeComponent = () => {
const [items, setItems] = React.useState([
{ name: 'qq', code: 'white' },
{ name: 'ww', code: 'white' },
{ name: `ee`, code: 'white' },
{ name: 'rr', code: 'white' },
{ name: 'tt', code: 'white' },
{ name: 'yy', code: 'white' },
{ name: 'uu', code: 'white' },
]);
return (
<FlatGrid
itemDimension={130}
data={items}
style={styles.gridView}
spacing={10}
renderItem={({ item }) => (
<View style={[styles.itemContainer, { backgroundColor: item.code }]}>
<PinIcon />
<CatIcon />
<Text style={styles.itemName}>{item.name}</Text>
<Text style={styles.itemCode}>{item.code}</Text>
</View>
)}
/>
);
};
Set the icon to items as icon props initially and to make the icon touchable, wrap icon with Pressable or TouchableOpacity and pass the function in onPress props like below
...
const [items, setItems] = React.useState([
{ name: 'qq', code: 'white', icon: <PinIcon/> },
{ name: 'ww', code: 'white', icon: <CatIcon/> },
{ name: `ee`, code: 'white', icon: <DogIcon/> },
...
]);
...
renderItem={({ item, index }) => (
<View style={[styles.itemContainer, { backgroundColor: item.code }]}>
<Pressable onPress={()=>onPressFunctionHere()}>
{item.icon}
</Pressable>
<Text style={styles.itemName}>{item.name}</Text>
<Text style={styles.itemCode}>{item.code}</Text>
</View>
)}
Related
In our App we use a tab navigation and a stack navigation for each tab. We want an array of devices where we could add and delete devices. The array should be available on every tab.
This is our provider
import React from 'react'
const DevicesContext = React.createContext('')
export default DevicesContext
This is our app.js
import React, {useState} from 'react';
import uuid from 'react-native-uuid';
import { NavigationContainer } from '#react-navigation/native';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import { MaterialCommunityIcons } from '#expo/vector-icons';
import { Feather } from '#expo/vector-icons';
import { MaterialIcons } from '#expo/vector-icons';
import HomeStackScreen from "./components/home/HomeStackScreen";
import ConnectStackScreen from "./components/connect/ConnectStackScreen";
import SettingsStackScreen from "./components/settings/SettingsStackScreen";
import DevicesContext from "./components/context/DevicesContext";
const Tab = createMaterialBottomTabNavigator();
const deleteItem = (id) => {
setDevices(prevDevice => {
return prevDevice.filter(device => device.id != id)
})
console.log(devices)
}
const addItem = (device) => {
setDevices(prevDevices => {
return [{id: uuid.v4(), name:device}, ...prevDevices];
})
}
function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Home"
activeColor="#E4E4E4"
inactiveColor="#000000"
shifting={true}
labelStyle={{ fontSize: 12 }}
barStyle={{ backgroundColor: '#8DFFBB' }}
>
<Tab.Screen
name="Devices"
component={ConnectStackScreen}
options={{
tabBarLabel: 'Geräte',
tabBarIcon: ({ color }) => (
<MaterialIcons name="devices" size={24} color={color} />
),
}}
/>
<Tab.Screen
name="Home"
component={HomeStackScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="home" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Settings"
component={SettingsStackScreen}
options={{
tabBarLabel: 'Einstellungen',
tabBarIcon: ({ color }) => (
<Feather name="settings" size={24} color={color} />
),
}}
/>
</Tab.Navigator>
);
}
export default function App() {
const [devices, setDevices] = useState([
{id: uuid.v4(), name: 'thing 1', ip: 5},
{id: uuid.v4(), name: 'thing 2', ip: 2},
{id: uuid.v4(), name: 'thing 3', ip: 6},
{id: uuid.v4(), name: 'thing 4', ip: 10},
])
return (
<DevicesContext.Provider value={devices}>
<NavigationContainer>
<MyTabs />
</NavigationContainer>
</DevicesContext.Provider>
);
}
this is our connect screen where we can add devices
import React, {useContext, useState} from 'react';
import {Text, View, Button, FlatList, StyleSheet, TouchableOpacity, Image} from 'react-native';
import uuid from 'react-native-uuid';
import ListItem from "../shared/ListItem";
import AddItem from "../shared/AddItem";
import DevicesContext from "../context/DevicesContext";
function ConnectScreen( {navigation}) {
const [devices, setDevices] = useState(useContext(DevicesContext));
const deleteItem = (id) => {
setDevices(prevDevice => {
return prevDevice.filter(device => device.id != id)
})
console.log(devices)
}
const addItem = (device) => {
setDevices(prevDevices => {
return [{id: uuid.v4(), name:device}, ...prevDevices];
})
}
return (
<View style={{padding: 10, flex: 1, justifyContent: 'center'}}>
<View style={styles.AddNormal}>
<AddItem addItem={addItem}></AddItem>
<FlatList style={styles.List} data={devices} renderItem={({item}) => (
<ListItem item={item} deleteItem={deleteItem}></ListItem>
)}/>
</View>
<View style={styles.AddQr}>
<Image source={require('../../img/qr-code-url.png')} style={{ width: 150, height: 150, marginBottom: 10 }} />
<Text style={{ textAlign: 'center', marginBottom: 10 }}>Du kannst außerdem ein Gerät durch das scannen eines Qr-Code hinzufügen</Text>
<TouchableOpacity onPress={() => navigation.navigate('QrCode')}style={styles.btn}>
<Text style={styles.btnText}>Qr-Code scannen</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
List: {
backgroundColor: '#E4E4E4',
},
AddNormal: {
padding: 10, flex: 1,
},
AddQr: {
backgroundColor: '#E4E4E4',
padding: 30,
flex: 1,
marginTop: 20,
marginBottom: 20,
alignItems: 'center'
},
btn: {
backgroundColor: '#8DFFBB',
padding: 9,
margin: 10,
},
btnText: {
color: '#000',
fontSize: 20,
textAlign: 'center',
}
});
export default ConnectScreen;
and this is our main screen
import React, {useState, useContext, useEffect} from 'react';
import {Button, FlatList, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View} from "react-native";
import {ServerOnOffSwitch, SendMessage} from "./network";
import DevicesContext from "../context/DevicesContext";
const Item = ({ item, onPress, backgroundColor, textColor }) => (
<TouchableOpacity onPress={onPress} style={[styles.item, backgroundColor]}>
<Text style={[styles.title, textColor]}>{item.name}</Text>
</TouchableOpacity>
);
function HomeScreen (){
const [devices, setDevices] = useState(useContext(DevicesContext));
const deleteItem = (id) => {
setDevices(prevDevice => {
return prevDevice.filter(device => device.id != id)
})
}
const [selectedId, setSelectedId] = useState(null);
const renderItem = ({ item }) => {
const backgroundColor = item.id === selectedId ? "#b5b5b5" : "#ededed";
const color = item.id === selectedId ? 'white' : 'black';
return (
<Item
item={item}
onPress={() => setSelectedId(item.id)}
backgroundColor={{ backgroundColor }}
textColor={{ color }}
/>
);
};
return (
<View style={{padding: 10, flex: 1, justifyContent: 'center'}}>
<View style={{padding: 10, flex: 1}}>
<Text style={styles.DeviceHeader}>Gerät auswählen</Text>
<FlatList
data={devices}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
/>
</View>
<View style={{padding: 10, flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<SendMessage item={selectedId}></SendMessage>
<ServerOnOffSwitch></ServerOnOffSwitch>
</View>
</View>
);
}
const styles = StyleSheet.create({
DeviceHeader: {
fontSize: 22,
paddingBottom: 10,
},
item: {
padding: 10,
backgroundColor: '#f8f8f8',
borderBottomWidth: 1,
borderColor: '#eee',
},
title: {
fontSize: 18,
},
});
export default HomeScreen;
If we add devices in our Connect screen they are getting updated there but not on the homescreen.
Thanks for your help:)
to update context from nested component you must pass the methode setDevices tha will update it.
to pass it do the following steps :
your context shoud be
import React from 'react'
const DevicesContext = React.createContext({
devices: [],
setDevices: () => {}, //methode will update context value
})
export default DevicesContext
App.js should be
//define state
const [devices, setDevices] = React.useState([])
//define constexValue
//we will pass `devices` and also `setDevices` that will update it.
const DevicesContextValue = React.useMemo(() => ({ devices, setDevices}), [devices]);
return (
<DevicesContext.Provider value={DevicesContextValue}>
...
</DevicesContext.Provider>
);
ConnectScreen.js should be
function ConnectScreen(){
const {devices, setDevices} = useContext(DevicesContext);
//call setDevices will update context
....
}
HomeScreen.js should be
function HomeScreen (){
const {devices, setDevices} = useContext(DevicesContext);
//use devices from context in your flatlist and when the context update the result will show in flatlist
....
}
In my RN application, I have the following array.
const PDFItems = [
{ id: 1001, name: 'APPLICATION FORM.PDF', size: '2.77 MB' },
{ id: 1002, name: 'BENEFIT ILLUSTRATION.PDF', size: '368 KB' },
{ id: 1003, name: 'PRODUCT SUMMARY.PDF', size: '2.02 MB' },
{ id: 1004, name: 'TERMS AND CONDITIONS.PDF', size: '269 KB' },
];
I created the following function to render items.
renderPDFItems = () => {
return PDFItems.map(item => (
<ListItem
key={item.id.toString()}
icon={<Download />}
title={item.name}
label={item.size}
onPress={() => {}}
/>
));
}
This is my ListItem component.
import React, { Component } from 'react';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
import colors from 'res/colors';
import SinglifeText from './text';
interface IProps {
title: string;
label: string;
icon: Object;
key: string;
onPress?: Function;
}
class ListItem extends Component<IProps> {
render() {
const { title, label, icon, key, onPress } = this.props;
return (
<TouchableOpacity onPress={onPress} key={key}>
<View style={styles.itemContainer}>
<View style={styles.titleContainer}>
<View style={styles.icon}>{icon}</View>
<SinglifeText type={SinglifeText.Types.BUTTON_LBL} label={title} />
</View>
<SinglifeText type={SinglifeText.Types.BODY_SMALL} label={label} />
</View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
itemContainer: {
borderColor: colors.gray,
borderRadius: 4,
borderWidth: 0.5,
padding: 14,
paddingVertical: 24,
flexDirection: 'row',
alignContent: 'center',
alignItems: 'center',
marginBottom: 10,
},
titleContainer: {
flex: 1,
flexDirection: 'row',
alignContent: 'center',
alignItems: 'center',
},
icon: {
marginRight: 10,
},
});
export default ListItem;
When I run the app, it shows a warning saying that,
key is not a prop. Trying to access it will result in undefined being returned. If you need to access the same value within the child component, you should pass it as a different prop
What am I doing wrong here? My keys are unique and still gives this error.
Just dont name the prop key. Something like id has the same syntactic meaning.
renderPDFItems = () => {
return PDFItems.map(item => (
<ListItem
id={item.id.toString()}
icon={<Download />}
title={item.name}
label={item.size}
onPress={() => {}}
/>
));
}
ListItem.js
class ListItem extends Component<IProps> {
render() {
const { title, label, icon, id, onPress } = this.props;
return (
<TouchableOpacity onPress={onPress} key={id}>
<View style={styles.itemContainer}>
<View style={styles.titleContainer}>
<View style={styles.icon}>{icon}</View>
<SinglifeText type={SinglifeText.Types.BUTTON_LBL} label={title} />
</View>
<SinglifeText type={SinglifeText.Types.BODY_SMALL} label={label} />
</View>
</TouchableOpacity>
);
}
}
It seems your key prop defined is ambiguous to TouchableOpacity key={key}. Try renaming key prop to some other name.
As some guys have said above, we don't need the key prop. TouchableOpacity has the key by default, and we can't use key another prop as 'key'
I did find this question in a few other places, but I'm still unable to resolve the issue with any of the help given. I got most of the code so far from this article -
https://medium.com/#austinhale/building-a-mobile-app-in-10-days-with-react-native-c2a7a524c6b4
Some of the APIs were outdated, but most of them I was able to replace with the new version - One of the APIs i changed that might be notable in regards to this question is stackNavigator -> createStackNavigator
My code is as follows:
Apps.js
import React, { Component } from 'react';
import {
FlatList,
StatusBar,
StyleSheet,
Text,
View
} from 'react-native';
import AppItem from './AppItem';
export default class Apps extends Component {
constructor(props) {
super(props);
this.state = {
apps: [
{
id: 1,
title: 'Good Business',
description: 'Make millions investing in mindtree minds',
thumbnail: 'https://img12.androidappsapk.co/300/f/5/1/com.nse.bse.sharemarketapp.png'
},
{
id: 2,
title: 'Troll WhatsApp SOS ONLY',
description: 'Have a laugh by reading all the comments in the group chat made by your coworkers',
thumbnail: 'http://icons.iconarchive.com/icons/dtafalonso/android-l/256/WhatsApp-icon.png'
}
]
}
}
_renderItem = ({ item }) => (
<AppItem
id={item.id}
title={item.title}
description={item.description}
thumbnail={item.thumbnail}
/>
);
_keyExtractor = (item, index) => item.id.toString();
render() {
return (
<View style={styles.container}>
<StatusBar
barStyle="light-content"
/>
<FlatList
data={this.state.apps}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
}
});
router.js
import React, { Component } from 'react';
import { Dimensions, Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import { Icon } from 'react-native-elements';
import Apps from './screens/Apps';
import Gallery from './screens/Gallery';
import Garage from './screens/Garage';
import News from './screens/News';
import Support from './screens/Support';
import ViewApp from './screens/ViewApp';
let screen = Dimensions.get('window');
export const Tabs = createBottomTabNavigator({
'Apps': {
screen: Apps,
navigationOptions: {
tabBarLabel: 'Apps',
tabBarIcon: ({ tintColor }) => <Icon raised name="ios-apps-outline" type="ionicon" size={28} color={tintColor} />
},
},
'News': {
screen: News,
navigationOptions: {
tabBarLabel: 'News',
tabBarIcon: ({ tintColor }) => <Icon raised name="newspaper-o" type="font-awesome" size={28} color={tintColor} />
},
},
'Garage': {
screen: Garage,
navigationOptions: {
tabBarLabel: 'Garage',
tabBarIcon: ({ tintColor }) => <Icon raised name="garage" type="material-community" size={28} color={tintColor} />
},
},
'Gallery': {
screen: Gallery,
navigationOptions: {
tabBarLabel: 'Gallery',
tabBarIcon: ({ tintColor }) => <Icon raised name="picture" type="simple-line-icon" size={28} color={tintColor} />
},
},
'Support': {
screen: Support,
navigationOptions: {
tabBarLabel: 'Support',
tabBarIcon: ({ tintColor }) => <Icon raised name="ios-person-outline" type="ionicon" size={28} color={tintColor} />
},
},
});
export const AppsStack = createStackNavigator({
Apps: {
screen: Apps,
navigationOptions: ({ navigation }) => ({
header: null,
}),
},
ViewApp: {
screen: ViewApp,
navigationOptions: ({ navigation }) => ({
header: null,
tabBarVisible: false,
gesturesEnabled: false
}),
},
});
export const createRootNavigator = () => {
return createStackNavigator(
{
AppsStack: {
screen: AppsStack,
navigationOptions: {
gesturesEnabled: false
}
},
Tabs: {
screen: Tabs,
navigationOptions: {
gesturesEnabled: false
}
}
},
{
headerMode: "none",
mode: "modal"
}
);
};
AppItem.js
import React, { Component } from 'react';
import {
StyleSheet,
TouchableOpacity,
Text,
Image,
View
} from 'react-native';
import { Icon } from 'react-native-elements';
import { ViewApp } from './ViewApp';
export default class AppItem extends Component {
_onViewApp = () => {
let id = this.props.id;
this.props.navigation.navigate('ViewApp', { id: id })
}
render() {
return (
<TouchableOpacity onPress={this._onViewApp}>
<View style={styles.rowContainer}>
<Image source={{ uri: this.props.thumbnail }}
style={styles.thumbnail}
resizeMode="contain" />
<View style={styles.rowText}>
<Text style={styles.title} numberOfLines={2} ellipsizeMode={'tail'}>
{this.props.title}
</Text>
<Text style={styles.description} numberOfLines={2} ellipsizeMode={'tail'}>
{this.props.description}
</Text>
</View>
</View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
rowContainer: {
flexDirection: 'row',
backgroundColor: '#FFF',
height: 100,
padding: 10,
marginRight: 10,
marginLeft: 10,
marginTop: 15,
borderRadius: 4,
shadowOffset: { width: 1, height: 1, },
shadowColor: '#CCC',
shadowOpacity: 1.0,
shadowRadius: 1
},
title: {
paddingLeft: 10,
paddingTop: 5,
fontSize: 16,
fontWeight: 'bold',
color: '#777'
},
description: {
paddingLeft: 10,
marginTop: 5,
fontSize: 14,
color: '#777'
},
thumbnail: {
flex: 1,
height: undefined,
width: undefined
},
rowText: {
flex: 4,
flexDirection: 'column'
}
});
You can change your onPress functionality in AppItem.js like below. Use arrow function inside your onPress onPress={() => this._onViewApp()}. Because Arrow function does not create the context "this". It refers to the context of the component that it was wrapped in. For lexical this refer this Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?
import { Icon } from 'react-native-elements';
import { ViewApp } from './ViewApp';
export default class AppItem extends Component {
_onViewApp(){
let id = this.props.id;
this.props.navigation.navigate('ViewApp', { id: id })
}
render() {
return (
<TouchableOpacity onPress={() => this._onViewApp()}>
<View style={styles.rowContainer}>
<Image source={{ uri: this.props.thumbnail }}
style={styles.thumbnail}
resizeMode="contain" />
<View style={styles.rowText}>
<Text style={styles.title} numberOfLines={2} ellipsizeMode={'tail'}>
{this.props.title}
</Text>
<Text style={styles.description} numberOfLines={2} ellipsizeMode={'tail'}>
{this.props.description}
</Text>
</View>
</View>
</TouchableOpacity>
);
}
}
I wanted to follow up for everyone who's having the same issue. I just included withNavigation from 'react-native-navigation'; and exported at the end of the component like so export default withNavigation(AppItem);.
I am trying to pass some row data from a list to next screen to display details but cannot seem to achieve it.
This is how i pass props when navigating like:
_renderRow(row,sectionId, rowId, highlightRow) {
var self = this;
let navigate=this.props.navigation;
return (
<TouchableOpacity onPress={() => navigate('ChatList',{row})}>
........//ignored code
And on the other screen ChatList.js:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
TextInput,
Image
} from 'react-native';
import { StackNavigator } from 'react-navigation';
const ChatList = () => {
return (
<View>
</View>
);
}
ChatList.navigationOptions = {
//trying to set the title from the data sent around here
title: 'ChatList Title',
headerStyle: {
backgroundColor: '#2196F3',
},
headerTitleStyle: {
color: 'white',
},
headerBackTitleStyle: {
color: 'white',
},
headerTintColor: 'white',
};
export default ChatList
Also to note, i have a different implementation on stacknavigation unlike the docs from reactnavigation .Checkout my entire implementation here https://gist.github.com/SteveKamau72/f04b0a3dca03a87d604fe73767941bf2
Here is the full class from which _renderRow resides:
ChatGroup.js
/** ChatGroup.js**/
//This code is component for file App.js to display group of chats
import React, { Component } from 'react';
import {
StyleSheet,
ListView,
Text,
View,
Image,
TouchableOpacity
} from 'react-native';
const data = [
{
name: "Kasarini",
last_chat: {
updated_at:"22:13",
updated_by: "Steve Kamau",
chat_message: "Lorem Ipsum is pretty awesome if you know it"
},
thumbnail: "https://randomuser.me/api/portraits/thumb/men/83.jpg"
},
{
name: "Kabete",
last_chat: {
updated_at:"20:34",
updated_by: "Tim Mwirabua",
chat_message: "Lorem Ipsum is pretty awesome if you know it"
},
thumbnail: "https://randomuser.me/api/portraits/thumb/men/83.jpg"
},
{
name: "Kiambuu",
last_chat: {
updated_at:"19:22",
updated_by: "Maureen Chubi",
chat_message: "Lorem Ipsum is pretty awesome if you know it"
},
thumbnail: "https://randomuser.me/api/portraits/thumb/men/83.jpg"
},
{
name: "UnderPass",
last_chat: {
updated_at:"17:46",
updated_by: "Faith Chela",
chat_message: "Lorem Ipsum is pretty awesome if you know it"
},
thumbnail: "https://randomuser.me/api/portraits/thumb/men/83.jpg"
},
]
export default class UserListView extends Component {
constructor() {
super();
const ds = new ListView.DataSource({rowHasChanged: this._rowHasChanged});
this.state = {
dataSource: ds.cloneWithRows(data)
}
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderRow.bind(this)}
enableEmptySections={true} />
)
}
_renderRow(row,sectionId, rowId, highlightRow) {
var self = this;
return (
<TouchableOpacity activeOpacity={0.9} onPress={() => navigate('ChatList',{ user: 'Lucy' })}>
<View style={styles.container}>
<Image
style={styles.groupChatThumbnail}
source={{uri: row.thumbnail}}/>
<View>
<View style={{flexDirection:'row', justifyContent:'space-between', width:280}}>
<Text style={styles.groupNameText}>{row.name} </Text>
<Text style={styles.groupUpdatedAtText}>{row.last_chat.updated_at}</Text>
</View>
<View style={{ flexDirection:'row', alignItems:'center', marginTop: 5}}>
<Text style={styles.groupUpdatedByText}>{row.last_chat.updated_by} : </Text>
<View style={{flex: 1}}>
<Text ellipsizeMode='tail' numberOfLines={1}style={styles.groupChatMessageText}>{row.last_chat.chat_message} </Text>
</View>
</View>
</View>
</View>
</TouchableOpacity>
)
}
_rowHasChanged(r1, r2) {
return r1 !== r2
}
highlightRow() {
alert('Hi!');
}
}
const styles = StyleSheet.create({
container:{
alignItems:'center',
padding:10,
flexDirection:'row',
borderBottomWidth:1,
borderColor:'#f7f7f7',
backgroundColor: '#fff'
},
groupChatContainer:{
display: 'flex',
flexDirection: 'row',
},
groupNameText:{
marginLeft:15,
fontWeight:'600',
marginTop: -8,
color: '#000'
},
groupUpdatedAtText :{
color:'#333', fontSize:10, marginTop: -5
},
groupChatThumbnail:{
borderRadius: 30,
width: 50,
height: 50 ,
alignItems:'center'
},
groupUpdatedByText:{
fontWeight:'400', color:'#333',
marginLeft:15, marginRight:5
},
});
There are two ways to access navigation props on second screen:
Inside like
navigationOptions = ({navigation}) => ({title:`${navigation.state.params.name}`});
If you access inside any method like render etc is
{user}= this.props.navigation.state.params
ChatList.navigationOptions this could written be as
ChatList.navigationOptions= ({navigation}) => ({// props access here });
and const ChatList = () inside this you can write this.props.navigation.state.params
I'm using React Native and react-native-elements to render a list of options in a side menu, however when I run the project, the onPress prop in ListItem fails to act as it should. The three console logs seem to iterate automatically with the main content on the screen when run, but when the side menu is opened the list items cannot be pressed and nothing further is logged in the console. Is there something wrong with my onPress function?
import { SideMenu, List, ListItem } from 'react-native-elements';
import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { MaterialIcons } from '#expo/vector-icons';
export default class Home extends Component {
state = {
toggled: false,
}
toggleSideMenu () {
this.setState({
toggled: !this.state.toggled
})L
render() {
const list = [
{
name: 'Profile',
pic: 'assignment-ind',
//nav: this.props.navigation.navigate('Profile', { user: this.state.user })
nav: console.log('pressing Profile!'),
},
{
name: 'Settings',
pic: 'settings-applications',
nav: console.log('pressing Settings!'),
},
{
name: 'Logout',
//nav: firebase.auth().signOut() // sign user out
nav: console.log('pressing Logout!'),
}
]
const MenuComponent = (
<View style={{flex: 1, backgroundColor: 'white', paddingTop: 10}}>
<List containerStyle={{marginBottom: 20}}>
{
list.map((item, i) => (
<ListItem
onPress={() => item.nav}
leftIcon={{ name: item.pic }}
key={i}
title={item.name}
/>
))
}
</List>
</View>
);
return (
<SideMenu
menu={MenuComponent}
toggled={this.state.toggled}>
<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
<TouchableHighlight
style={{marginTop: 20, marginLeft: 9}}
onPress={this.toggleSideMenu.bind(this)}
underlayColor='transparent'>
<MaterialIcons
color='white'
name='menu'
size={28}
/>
</TouchableHighlight>
</View>
</View>
</SideMenu>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'black',
},
});
Figured it out:
I made each proper methods within the list object:
const list = [
{
name: 'Profile',
pic: 'assignment-ind',
//nav: this.props.navigation.navigate('Profile', { user: this.state.user })
nav: () => { console.log('pressing Profile!'); },
},
{
name: 'Settings',
pic: 'settings-applications',
nav: () => { console.log('pressing Settings!'); },
},
{
name: 'Logout',
//nav: firebase.auth().signOut() // sign user out
nav: () => { console.log('pressing Logout!'); },
}
Then I added parentheses to the onPress function:
onPress={() => item.nav()}
onPress has to be a method. You need to make nav of the list a method by binding it there itself. For eg.
nav : () => {console.log("Logout pressed")}
Also you need to call it from onPress.
onPress : item.nav() // Note the brackets.
Happy coding.