when i run it in expo it says "can't find variable navigation" , I can't seem to figure out why navigation isn't working does anyone have any ideas? I've tried taking this.props away etc but that doesn't work either
'use strict'
import React, { Component } from 'react';
import {
Text,
TextInput,
TouchableHighlight,
StatusBar,
ListView,
FlatList,
View
} from 'react-native';
import firebaseApp from './firebaseConfig.js';
import styles from './styles.js';
class Rooms extends Component {
static navigationOptions = {
title: 'Rooms',
header: null
};
constructor(props) {
super(props);
var firebaseDB = firebaseApp.database();
this.roomsRef = firebaseDB.ref('rooms');
this.state = {
rooms: [],
newRoom: ''
}
}
componentDidMount() {
this.listenForRooms(this.roomsRef);
}
listenForRooms(roomsRef) {
roomsRef.on('value', (dataSnapshot) => {
var roomsFB = [];
dataSnapshot.forEach((child) => {
roomsFB.push({
name: child.val().name,
key: child.key
});
});
this.setState({ rooms: roomsFB });
});
}
addRoom() {
if (this.state.newRoom === '') {
return;
}
this.roomsRef.push({ name: this.state.newRoom });
this.setState({ newRoom: '' });
}
openMessages(room) {
this.props.navigation.navigate('Messages', {roomKey: room.key, roomName: room.name});
}
renderRow(item) {
return (
<TouchableHighlight style={styles.roomLi}
underlayColor="#fff"
onPress={() => this.openMessages(item)}
>
<Text style={styles.roomLiText}>{item.name}</Text>
</TouchableHighlight>
)
}
render() {
return (
<View style={styles.roomsContainer}>
<StatusBar barStyle="light-content"/>
<Text style={styles.roomsHeader}>Chatypus</Text>
<View style={styles.roomsInputContainer}>
<TextInput
style={styles.roomsInput}
placeholder={"New Room Name"}
onChangeText={(text) => this.setState({newRoom: text})}
value={this.state.newRoom}
/>
<TouchableHighlight style={styles.roomsNewButton}
underlayColor="#fff"
onPress={() => this.addRoom()}
>
<Text style={styles.roomsNewButtonText}>Create</Text>
</TouchableHighlight>
</View>
<View style={styles.roomsListContainer}>
<FlatList
data={this.state.rooms}
renderItem={({item}) => (this.renderRow(item)
)}
/>
</View>
</View>
);
}
}
export default Rooms;
Related
Here is a picture of the screen When I try to render my timestamp from firestore it shows an error
"Objects are not valid as a React child (found: object with keys {seconds, nanoseconds}. If you meant to render a collection of children, use an array instead." How do I format my code to display my timestamp from the Firestore. I am able to create the timestamp and read it in my firestore dashboard.
import React, { Component } from "react";
import {
StyleSheet,
ScrollView,
ActivityIndicator,
View,
Text,
} from "react-native";
import { List, NativeBaseProvider } from "native-base";
import { ListItem } from "react-native-elements";
import colors from "../config/colors";
import firebase from "../../firebase";
class SearchEntry extends Component {
constructor() {
super();
this.firestoreRef = firebase.firestore().collection("RepairDocuments");
this.state = {
isLoading: true,
entryArr: [],
};
}
componentDidMount() {
this.unsubscribe = this.firestoreRef.onSnapshot(this.getCollection);
}
componentWillUnmount() {
this.unsubscribe();
}
getCollection = (querySnapshot) => {
const entryArr = [];
querySnapshot.forEach((res) => {
const { unit, datetime, bio } = res.data();
entryArr.push({
key: res.id,
res,
unit,
datetime,
bio,
});
});
this.setState({
entryArr,
isLoading: false,
});
};
render() {
if (this.state.isLoading) {
return (
<View style={styles.preloader}>
<ActivityIndicator size="large" color="#9E9E9E" />
</View>
);
}
return (
<ScrollView style={styles.container}>
{this.state.entryArr.map((res, i) => {
return (
<ListItem
key={i}
onPress={() => {
this.props.navigation.navigate("Details", {
userkey: res.key,
});
}}
bottomDivider
>
<ListItem.Content>
<ListItem.Title>{res.unit}</ListItem.Title>
<ListItem.Subtitle>{new Date(res.datetime?.unixTime * 1000).toLocaleDateString(
""
)}</ListItem.Subtitle>
</ListItem.Content>
<ListItem.Chevron color="black" />
</ListItem>
);
})}
</ScrollView>
);
}
}
Here is the code that enters the time stamp to my firestore.
import React, { Component, useState } from "react";
import {
ImageBackground,
View,
StyleSheet,
TextInput,
TouchableOpacity,
Image,
ActivityIndicator,
Text,
} from "react-native";
import LargeButton from" .. / components /LargeButton";
import colors from "../config/colors";
import firebase from "../../firebase";
import DatePicker from "#react-native- community/datetimepicker";
class CreateEntry extends Component {
constructor() {
super();
this.dbRef = firebase.firestore().collection("RepairDocuments");
this.state = {
unit: "",
datetime: new Date(),
bio: "",
isLoading: false,
};
}
onChange = (event, selectedDate) => {
const showFlag = Platform.OS === "ios";
this.setState({ show: showFlag });
this.inputValueUpdate(selectedDate, "datetime");
};
inputValueUpdate = (val, prop) => {
const state = this.state;
state[prop] = val;
this.setState(state);
};
storeEntry() {
if (this.state.unit === "") {
alert("Please fill out unit #");
} else {
this.setState({
isLoading: true,
});
this.dbRef
.add({
unit: this.state.unit,
datetime: this.state.datetime,
bio: this.state.bio,
})
.then((res) => {
this.setState({
unit: "",
datetime: new Date(),
bio: "",
isLoading: false,
});
this.props.navigation.navigate("Home");
})
.catch((err) => {
console.error("Error found: ", err);
this.setState({
isLoading: false,
});
});
}
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.preloader}>
<ActivityIndicator size="large" color="#9E9E9E" />
</View>
);
showMode = (currentMode) => {
this.setState({ show: true });
this.setState({ mode: currentMode });
};
showDatepicker = () => {
this.showMode("date");
};
}
return (
<ImageBackground
style={styles.background}
source={require("../assets/Login.jpeg")}
>
<View style={styles.container}>
<View style={styles.header}>
<Image
style={styles.headerLogo}
source={require("../assets/WordLogo.jpeg")}
/>
</View>
<View style={styles.inputGroup}>
<TextInput
placeholder={"Enter Unit #"}
value={this.state.unit}
onChangeText={(val) => this.inputValueUpdate(val, "unit")}
/>
</View>
<View style={styles.inputGroup}>
<Text>Select Date:</Text>
<View>
<DatePicker
testID="dateTimePicker"
value={this.state.datetime}
display="default"
onChange={this.onChange}
dateFormat="dd/MM/yyyy h:mm aa"
/>
</View>
</View>
<View style={styles.inputGroup}>
<TextInput
placeholder={"Enter Work Completed"}
value={this.state.bio}
onChangeText={(val) => this.inputValueUpdate(val, "bio")}
/>
</View>
<LargeButton
title="submit"
color="secondary"
onPress={() => this.storeEntry()}
/>
</View>
</ImageBackground>
);
}
}
if i change the language from my setting screen inside my app, it does not change the language for already opened routes in my application. the language change is only reflect on unopened routes. i used react-native-localize and i18n-js. Given below my code
index.js
import * as RNLocalize from 'react-native-localize';
import I18n from 'i18n-js';
import memoize from 'lodash.memoize';
import {I18nManager,
AsyncStorage} from 'react-native';
import en from './en';
import am from './am';
import or from './or';
import tg from './tg';
import sl from './sl';
const locales = RNLocalize.getLocales();
if (Array.isArray(locales)) {
I18n.locale = locales[0].languageTag;
}
I18n.fallbacks = true;
I18n.translations = {
default: en,
'en-US': en,
en,
am,
or,
tg,
sl,
};
export default I18n;
My SettingScreen where i can change the language is:
SettingScreen.js
const listLanguage = [
{key:'en', label:'En'}, {key:'am', label:'Am'} ,{key:'or', label: 'Or'}, {key:'tg', label:'TG'},]
export default class SettingsScreen extends React.Component {
constructor(props) {
super(props);
this.state = { visible: true ,
languageSelected: 'en'
};
}
backToMain() {
this.props.navigation.navigate('LocationTrackingScreen', {});
}
handleBackPress = () => {
this.props.navigation.navigate('LocationTrackingScreen', {});
return true;
};
hideSpinner() {
this.setState({ visible: false });
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
}
onChangeLanguage(languageSelected){
this.setState({
languageSelected
})
I18n.locale = languageSelected
}
render() {
const {languageSelected} = this.state
return (
<SafeAreaView style={styles.container}>
<View style={styles.headerContainer}>
<TouchableOpacity
style={styles.backArrowTouchable}
onPress={() => this.backToMain()}>
<Image style={styles.backArrow} source={backArrow} />
</TouchableOpacity>
<Text style={styles.headerTitle}>{I18n.t('setting.setting_title')}</Text>
</View>
<View style={styles.containerLangSelect}>
<Text style={styles.sectionDescription}>{I18n.t('setting.select_language')}</Text>
</View>
<View style={styles.containerDropdown}>
<DropdownLanguage language={languageSelected} onChangeLanguage={this.onChangeLanguage.bind(this)}></DropdownLanguage>
</View>
</SafeAreaView>
);
}
}
class DropdownLanguage extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<View style={styles.dropdownLanguage}>
{/* <Text style={{width:10,}}>{I18n.t('setting.select_language')}: </Text> */}
<Picker
mode="dropdown"
iosHeader={''}
style={{ width: width,
}}
selectedValue={this.props.language}
onValueChange={this.props.onChangeLanguage.bind(this)}
>
{listLanguage.map((languageItem, i) => {
return <Picker.Item key={i} value={languageItem.key} label= {languageItem.label} />
})}
</Picker>
</View>
)
}
}
I want to render my contact list in my app using expo-contacts, the list display for about 2 seconds, then i get typeError: undefined is not an object (evaluating 'item.phoneNumbers[0]'). I have checked the documentation to see if I made any errors, but i could not find any. Does anyone have a work around this
below is my code
ContactList.js
import React, { Component } from "react";
import {
View,
Text,
Platform,
StatusBar,
FlatList,
StyleSheet,
ActivityIndicator
} from "react-native";
import * as Contacts from "expo-contacts";
import * as Permissions from "expo-permissions";
class ContactList extends Component {
static navigationOptions = {
header: null
};
constructor(props) {
super(props);
this.state = {
isLoading: false,
contacts: []
};
}
async componentDidMount() {
this.setState({
isLoading: true
});
this.loadContacts();
}
loadContacts = async () => {
const permissions = await Permissions.askAsync(Permissions.CONTACTS);
if (permissions.status !== "granted") {
return;
}
const { data } = await Contacts.getContactsAsync({
fields: [Contacts.Fields.PhoneNumbers, Contacts.Fields.Emails]
});
this.setState({
contacts: data,
isLoading: false
});
};
handleBack() {
this.props.navigation.goBack();
}
renderItem = ({ item }) => (
<View style={{ minHeight: 70, padding: 5 }}>
<Text>
{item.firstName}
{item.lastName}
</Text>
<Text>{item.phoneNumbers[0].digits}</Text>
</View>
);
render() {
const { isLoading, contacts } = this.state;
let emptyContact = null;
emptyContact = (
<View style={styles.emptyContactStyle}>
<Text style={{ color: "red" }}>No Contacts Found</Text>
</View>
);
return (
<SafeAreaView style={styles.contentWrapper}>
<View style={styles.contentWrapper}>
{isLoading ? (
<View style={styles.isLoadingStyle}>
<ActivityIndicator size="large" color="#2484E8" />
</View>
) : null}
<FlatList
data={contacts}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
ListEmptyComponent={emptyContact}
/>
</View>
</SafeAreaView>
);
}
}
Here is a new answer because the previous one was off topic. The error occurs because the displayed contact doesn't have a phoneNumber.
You should check first that a phone number exists before displaying it:
renderItem = ({ item }) => (
<View style={{ minHeight: 70, padding: 5 }}>
<Text>
{item.firstName}
{item.lastName}
</Text>
<Text>
{item.phoneNumbers && item.phoneNumbers[0] && item.phoneNumbers[0].digits}
</Text>
</View>
);
I'm using React native navigation. (Stack Navigation).
But I can't call function in navigationOptions. Not working.
import React, { Component } from 'react';
import { StyleSheet, View, Text, TouchableHighlight, AsyncStorage, Alert } from 'react-native';
import { Button } from 'react-native-elements';
import Icon from 'react-native-vector-icons/FontAwesome';
import HandleBack from '../../HandleBack';
export default class Dashboard extends Component {
constructor(props) {
super(props);
}
static navigationOptions = ({ navigation }) => {
return {
title: 'Dasboard',
headerLeft: null,
headerRight: (
<TouchableHighlight underlayColor='transparent' onPress={this.login.bind(this)} style={{marginRight: 10}}>
<Icon
name="power-off"
size={25}
color="white"
/>
</TouchableHighlight>
)
};
};
login() {
alert('Button clicked!');
}
onBack = () => {
this.props.navigation.navigate('Screen3');
};
render() {
return(
<HandleBack onBack={ this.onBack }>
<View>
<Text> This is screen 2 </Text>
<TouchableHighlight onPress={() => this.props.navigation.navigate('Screen3')}>
<Text> Go to Screen 3 </Text>
</TouchableHighlight>
</View>
</HandleBack>
)
}
}
When I'm using onPress={this.login.bind(this)} get error
"TypeError: TypeError: undefined is not an object (evaluatinh '_class.login.bind')"
When I'm using onPress={this.login} no reaction.
When I'm using onPress={this.login()} get error
TypeError: TypeError: _class.login is not a function.
But
I'm using onPress={() => alert('test')} is working.
you can achieve it using setParams or getParams for react-navigation.
export default class Dashboard extends Component {
static navigationOptions = ({ navigation }) => {
return {
title: 'Dasboard',
headerLeft: null,
headerRight: (
<TouchableHighlight underlayColor='transparent'
onPress={navigation.getParam('login')} //call that function in onPress using getParam which we already set in componentDidMount
style={{marginRight: 10}}>
<Icon
name="power-off"
size={25}
color="white"
/>
</TouchableHighlight>
)
};
};
login() {
alert('login click')
}
onBack = () => {
this.props.navigation.navigate('Screen3');
};
componentDidMount() {
this.props.navigation.setParams({ login: this.login }); //initialize your function
}
render() {
return(
.....
)
}
}
iam new in react native and start my first project , i have a login screen and when i press into TouchableHighlight i need to open another screen , but the problem is i failed to make the function that move from login to second screen , this is my code
Login.js
import React, { Component } from 'react';
import { AppRegistry, Text,SecureView ,Button,Image,TextInput,StyleSheet,View,NavigatorIOS,TouchableHighlight} from 'react-native';
require('./HygexListView.js');
class LoginView extends Component {
constructor(props){
super(props);
}
onPositive(){
this.props.navigator.pop()
};
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>
HYGEX
</Text>
<View>
<TextInput
placeholder="Username"
style={styles.formInput}
/>
<TextInput
placeholder="Password"
secureTextEntry={true}
style={styles.formInput1}
/>
<TouchableHighlight style={styles.button}
onPress={ () => this.onPositive() }>
<Text style={styles.buttonText}>Login</Text>
</TouchableHighlight>
</View>
</View>
);
}
onPress() {
this.props.navigator.push({
title: "HygexListView",
component: HygexListView,
});
}
}
and when press into TouchableHighlight i need to open this screen
HygexListView.js
'use strict';
import React, { Component } from 'react';
import { AppRegistry, ListView, Text, View } from 'react-native';
class HygexListView extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows([
'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
])
};
}
render() {
return (
<View style={{flex: 1, paddingTop: 22}}>
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
</View>
);
}
}
module.exports = HygexListView;
From what i see there, i think you forgot to use/setup the Navigator component. Try to organize it this way:
Your components
class HygexListView extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows([
'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
])
};
}
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={{backgroundColor: 'red', alignItems: 'center'}}
routeMapper={NavigationBarRouteMapper} />
} />
);
}
renderScene(route, navigator) {
return (
<View style={{flex: 1, paddingTop: 22}}>
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
</View>
);
}
}
module.exports = HygexListView;
index.ios.js
class yourApp extends Component {
render() {
return (
<Navigator
initialRoute={{id: 'Login'}}
renderScene={this.renderScene.bind(this)}
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.PushFromRight;
}} />
);
}
renderScene(route, navigator) {
switch (route.id) {
case 'HygexListView':
return (
<HygexListView navigator={navigator} />
);
case 'Login':
return (
<Login navigator={navigator} />
);
default:
return null;
}
}
}
basically what you do, instead of rendering your component, you render your navigator that using renderScene() renders your component/view.
the approach to use the index file as an organizer of the views, is just a preference of mine. but you will see there, that when an "id" is passed to the navigator, the scene will be rendered using the component that matches the id on the switch case.