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.
Related
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>
)}
I'm new to react. I have my App.js page that contains the main code, and a lists.js page in another folder that contains the list itself.
I import from lists.js into my App.js. It works fine.
I'm trying to set an onPress action for the listItems that also sends a unique ID to the next page that I can use to call out items in the new page.
For clarity, if i was to do this with a normal button, it will look like:
this.props.navigation.navigate('NextPage', { Email: UserEmail });
So how do i do this with a ListView that I imported from another file.
This is how my code is structured
App.js
import MarketList from './lists/markets';
class ProfileActivity extends Component
{
static navigationOptions =
{
title: 'Home',
headerStyle : {
backgroundColor: '#00b47a'
},
headerTitleStyle: {
color: 'white'
},
headerLeft: null,
headerRight: (
<Icon containerStyle={{ paddingRight: 15 }}
color='#000' onPress={()=> navigation.getParam('openBottomSheet')()}
name="menu" />
)
};
constructor () {
super()
this.state = { toggled: false }
}
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<MarketList />
</View>
);
}
}
My lists.js
export default class MarketList extends React.Component {
constructor(props) {
super(props)
this.state = {
items: '',
};
}
render() {
fetch('https://example.php')
.then((response) => response.json())
.then((json) => {
this.setState({
items: json.items,
})
})
.catch((error) => {
console.error(error);
});
return (
<View style={styles.container}>
<FlatList
data={this.state.items}
renderItem={({item}) => <TouchableOpacity onPress={} style={styles.itemList}><View style={styles.item}><Text style={styles.market}>{item.name}</Text><Text style={styles.location}>{item.Location}</Text></View><View style={styles.go}><Icon name="arrow-right" color="#00b47a" /></View></TouchableOpacity>}
/>
</View>
);
}
}
You can do something like below
Pass navigation as a prop to MarketList component
<MarketList navigation={this.props.navigation}/>
And use like below
renderItem={({item}) => <TouchableOpacity onPress={()=>this.props.navigation.navigate("pagename",{item:item})}
I want to use relamDb in my react native expo project. I run the following command to install realm in my project-
npm install --save realm
it doesn't show any error while installing. After installing, in my project I have created two classes - App.js and TodoListComponent.js
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import TodoListComponent from './components/TodoListComponent';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<TodoListComponent/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
TodoListComponent.js
import React, { Component } from 'react';
import { View, FlatList, Text, TouchableOpacity, StyleSheet, Alert } from 'react-native';
import { updateTodoList, deleteTodoList, queryAllTodoLists } from '../databases/allSchemas';
import realm from '../databases/allSchemas';
import Swipeout from 'react-native-swipeout';
import HeaderComponent from './HeaderComponent';
import PopupDialogComponent from './PopupDialogComponent';
let FlatListItem = props => {
const { itemIndex, id, name, creationDate, popupDialogComponent, onPressItem } = props;
showEditModal = () => {
popupDialogComponent.showDialogComponentForUpdate({
id, name
});
}
showDeleteConfirmation = () => {
Alert.alert(
'Delete',
'Delete a todoList',
[
{
text: 'No', onPress: () => { },//Do nothing
style: 'cancel'
},
{
text: 'Yes', onPress: () => {
deleteTodoList(id).then().catch(error => {
alert(`Failed to delete todoList with id = ${id}, error=${error}`);
});
}
},
],
{ cancelable: true }
);
};
return (
<Swipeout right={[
{
text: 'Edit',
backgroundColor: 'rgb(81,134,237)',
onPress: showEditModal
},
{
text: 'Delete',
backgroundColor: 'rgb(217, 80, 64)',
onPress: showDeleteConfirmation
}
]} autoClose={true}>
<TouchableOpacity onPress={onPressItem}>
<View style={{ backgroundColor: itemIndex % 2 == 0 ? 'powderblue' : 'skyblue' }}>
<Text style={{ fontWeight: 'bold', fontSize: 18, margin: 10 }}>{name}</Text>
<Text style={{ fontSize: 18, margin: 10 }} numberOfLines={2}>{creationDate.toLocaleString()}</Text>
</View>
</TouchableOpacity>
</Swipeout >
);
}
export default class TodoListComponent extends Component {
constructor(props) {
super(props);
this.state = {
todoLists: []
};
this.reloadData();
realm.addListener('change', () => {
this.reloadData();
});
}
reloadData = () => {
queryAllTodoLists().then((todoLists) => {
this.setState({ todoLists });
}).catch((error) => {
this.setState({ todoLists: [] });
});
console.log(`reloadData`);
}
render() {
return (<View style={styles.container}>
<HeaderComponent title={"Todo List"}
hasAddButton={true}
hasDeleteAllButton={true}
showAddTodoList={
() => {
this.refs.popupDialogComponent.showDialogComponentForAdd();
}
}
/>
<FlatList
style={styles.flatList}
data={this.state.todoLists}
renderItem={({ item, index }) => <FlatListItem {...item} itemIndex={index}
popupDialogComponent={this.refs.popupDialogComponent}
onPressItem={() => {
alert(`You pressed item `);
}} />}
keyExtractor={item => item.id}
/>
<PopupDialogComponent ref={"popupDialogComponent"} />
</View>);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
},
flatList: {
flex: 1,
flexDirection: 'column',
}
});
After these coding, when I run the application it shows the following error-
missing Realm constructor. Did you run "react-native link realm" ? Please see https://realm.io/docs/react-native/latest/#missing-realm-constructor for troubleshooting
I have tried to find out problem from the below links-
https://github.com/realm/realm-js/issues/1407
https://github.com/realm/realm-js/issues/1340
But none of these were helpful to me. So, it would be very nice if some one helps me to know how to use realmDb in React native expo project.
Expo does not support realm.
You will have to eject from expo and then start using realm
Please note that Expo does not support Realm, From the docs.
Old Question, but you can now by using their template:
https://www.npmjs.com/package/#realm/expo-template-ts
https://www.mongodb.com/docs/realm/sdk/react-native/quick-start-expo/
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'm using React Native Elements CheckBox inside List Items, of Flat List.
import React, { Component } from "react";
import { View, Text, StyleSheet, FlatList } from "react-native";
import axios from "axios";
import {
Button,
Container,
Content,
Header,
Body,
Left,
Right,
Title
} from "native-base";
import Icon from "react-native-vector-icons/Ionicons";
import { List, ListItem, SearchBar, CheckBox } from "react-native-elements";
// const itemId = this.props.navigation.getParam('itemId', 'NO-ID');
// const otherParam = this.props.navigation.getParam('otherParam', 'some default value');
class TeacherSubjectSingle extends Component {
static navigationOptions = {
header: null
};
// static navigationOptions = {
// headerStyle: {
// backgroundColor: '#8E44AD',
// },
// headerTintColor: '#fff',
// }
state = {
class_id: null,
userid: null,
usertype: null,
student_list: [],
faq: [],
checked: []
};
componentWillMount = async () => {
const {
class_id,
student_list,
userid,
usertype
} = this.props.navigation.state.params;
await this.setState({
class_id: class_id,
student_list: student_list,
userid: userid,
usertype: usertype
});
console.log(this.state.class_id);
var result = student_list.filter(function(obj) {
return obj.class_section_name == class_id;
});
this.setState({
student_list: result[0]
});
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE"
}}
/>
);
};
checkItem = item => {
const { checked } = this.state;
if (!checked.includes(item)) {
this.setState({ checked: [...checked, item] });
} else {
this.setState({ checked: checked.filter(a => a !== item) });
}
};
render() {
return (
<Container>
<Header style={{ backgroundColor: "#8E44AD" }}>
<Left>
<Button
transparent
onPress={() => this.props.navigation.navigate("ClassTeacher")}
>
<Icon name="ios-arrow-dropleft" size={24} color="white" />
</Button>
</Left>
<Body>
<Title style={{ color: "white" }}>{this.state.class_id}</Title>
</Body>
<Right />
</Header>
<View style={{ flex: 1, backgroundColor: "#fff" }}>
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={this.state.student_list.students}
renderItem={({ item }) => (
<ListItem
// roundAvatar
title={
<CheckBox
title={item.name}
onPress={() => this.checkItem(item.userid)}
checked={this.state.checked.includes(item.userid)}
/>
}
// subtitle={item.email}
// avatar={{ uri: item.picture.thumbnail }}
containerStyle={{ borderBottomWidth: 0 }}
onPress={() =>
this.props.navigation.navigate("IndividualChat", {
rc_id: item.userid,
userid: this.state.userid,
usertype: this.state.usertype,
subject_name: this.state.student_list.subject_name
})
}
/>
)}
keyExtractor={item => item.userid}
ItemSeparatorComponent={this.renderSeparator}
/>
</List>
</View>
</Container>
);
}
}
export default TeacherSubjectSingle;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
}
});
Above is my code for the same, I have tried every possibility and checked the GitHub page for the same, but my items are not getting checked if I press on the checkbox.
My renderItem will have an array to render which is having a field like 'name' and 'userid'.
This is the example of the code from where I have coppied the coding for the same, where it is working
I want to save selected ids to an array so that I can pass that as a prop to the next screen.
Since FlatList is a PureComponent, it will not re-render the items unless the data changes. If you want the FlatList to re-render when checked array changes, you need to pass it to e.g. extraData.
<FlatList
data={this.state.student_list.students}
extraData={this.state.checked}
renderItem={({ item }) => {
// ...
}}
keyExtractor={item => item.userid}
ItemSeparatorComponent={this.renderSeparator}
/>