React native TouchableHighlight on press open another screen - javascript

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.

Related

can't find variable navigation in react native

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;

React native, undefined is not an object And handle onChange

I made 2 screens home and editing screen. I want to change values from edit screen without redux and context but I don't know how? and also when I click save in editscreen it's throwing error that undefined is not an object (evaluating '_this.props.navigation.goBack') and displaing blank home screencwhy that's happening. Can some one help me please, below is my code
home.js
class Home extends Component {
state = {
modal: false,
editMode: false.
post: [
{
key: "1",
title: "A Good Boi",
des: "He's a good boi and every one know it.",
image: require("../assets/dog.jpg"),
},
{
key: "2",
title: "John Cena",
des: "As you can see, You can't see me!",
image: require("../assets/cena.jpg"),
},
],
};
addPost = (posts) => {
posts.key = Math.random().toString();
this.setState((prevState) => {
return {
post: [...prevState.post, posts],
modal: false,
};
});
};
onEdit = (data) => {
this.setState({ post: { title: data }, editMode: false });
};
render() {
if (this.state.editMode)
return <EditScreen item={item} onEdit={this.onEdit} />;
return (
<Screen style={styles.screen}>
<Modal visible={this.state.modal} animationType="slide">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalContainer}>
<AddPost addPost={this.addPost} />
</View>
</TouchableWithoutFeedback>
</Modal>
<FlatList
data={this.state.post}
renderItem={({ item }) => (
<>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.setState({ editMode: true })}
style={styles.Edit}
>
<MaterialCommunityIcons
name="playlist-edit"
color="green"
size={35}
/>
</TouchableOpacity>
<Card>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<Text style={styles.title} numberOfLines={1}>
{item.title}
</Text>
<Text style={styles.subTitle} numberOfLines={2}>
{item.des}
</Text>
</View>
</Card>
</>
)}
/>
</Screen>
Edit.js
import React, { Component } from "react";
import { View, StyleSheet, Image, KeyboardAvoidingView } from "react-native";
import colors from "../config/colors";
import AppButton from "../components/AppButton";
import AppTextInput from "../components/AppTextInput";
class EditScreen extends Component {
render() {
const { item, onEdit, onClose } = this.props;
return (
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === "ios" ? 0 : 100}
>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<AppTextInput value={item.title} />
<AppTextInput value={item.des} />
</View>
<AppButton
text="Save"
onPress={() => {
onEdit(this.state);
}}
/>
</KeyboardAvoidingView>
);
}
}
export default EditScreen;
AppTextInput.js
function AppTextInput({ icon, width = "100%", ...otherProps }) {
return (
<View style={[styles.container, { width }]}>
<TextInput
placeholderTextColor={defaultStyles.colors.medium}
style={defaultStyles.text}
{...otherProps}
/>
</View>
);
}
Try this:
Edit.js
import React, { Component } from 'react';
import { View, StyleSheet, Image, KeyboardAvoidingView } from 'react-native';
import colors from '../config/colors';
import AppButton from '../components/AppButton';
import AppTextInput from '../components/AppTextInput';
class EditScreen extends Component {
constructor(props) {
super(props);
this.state = { ...props.item };
}
render() {
const { onEdit, onClose } = this.props;
const { title, des, image } = this.state;
return (
<KeyboardAvoidingView
behavior="position"
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 100}>
<Image style={styles.image} source={image} />
<View style={styles.detailContainer}>
<AppTextInput
value={title}
onChangeText={text => this.setState({ title: text })}
/>
<AppTextInput
value={des}
onChangeText={text => this.setState({ des: text })}
/>
</View>
<AppButton text="Save" onPress={() => onEdit(this.state)} />
</KeyboardAvoidingView>
);
}
}
export default EditScreen;
onEdit
onEdit = data => {
const newPosts = this.state.post.map(item => {
if(item.key === data.key) return data;
else return item;
})
this.setState({ post: newPosts, editMode: false });
};
Only the direct children of a navigator can access
this.props.navigation
If you want to access that inside the edit screen you can pass it from the Home screen as a prop. Like so:
return <EditScreen item={item} onEdit={this.onEdit} navigation={this.props.navigation} />;
But i don't think you need to go back because you are still on the Home page and just rendering the EditScreen within it. So just changing the state to have editMode: false should be enough

changing the language of react native app does not change the language for already opened routes

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>
)
}
}

"undefined is not an object" when trying to access TextInput of the sibling component using references

in Parent component, I'm trying to focus the TextInput of second Child component when submit button is pressed in the TextInput of the first Child component but this error comes up: error message
Child.js
import React from "react";
import { View, TextInput} from "react-native";
export default class Child extends React.Component {
focus = ref => {
ref.input.focus();
};
render() {
return (
<View>
<TextInput
placeholder='enter text'
onSubmitEditing={() => {
this.focus(this.props.destinationRef);
}}
ref={input => {
this.input = input;
}}
/>
</View>
);
}
}
Parent.js
import React from "react";
import Child from "./Child";
import { View, StyleSheet } from "react-native";
export default class Parent extends React.Component {
// componentDidMount() {
// setTimeout(() => {
// this.two.input.focus();
// }, 3000);
// }
render() {
return (
<View style={styles.container}>
<Child
destinationRef={() => {
if (!this.two) return this.two;
}}
ref={input => {
this.one = input;
}}
/>
<Child ref={input => (this.two = input)} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
}
});
Note that when I uncomment the componendDidMount, second TextInput successfully focuses three seconds after mounting.
I think the problem in render update. In first render time destinationRef is undefined, parent state not updated or force updated so props not updated too.
I try little bit optimize your code. You can use arrow function to bind this:
import React from "react";
import Child from "./Child";
import { View, StyleSheet } from "react-native";
export default class Parent extends React.Component {
_makeFocus(){
this.two.input.focus();
}
handleOnSubmit(){
this._makeFocus();
}
render() {
return (
<View style={styles.container}>
<Child
onSubmit={this.handleOnSubmit.bind(this)}
ref={input => {
this.one = input;
}}
/>
<Child ref={input => (this.two = input)} />
</View>
);
}
}
I would change the logic a little bit since I think the ref is giving you problems.
Parent:
<View style={styles.container}>
<Child next={this.two} ref={comp => this.one = comp}/>
<Child next={this.one} ref={comp => this.two = comp}/>
</View>
Child:
<TextInput
placeholder='enter text'
onSubmitEditing={() => {
if (this.props.next)
this.props.next.focus();
}}
/>
EDIT:
Your approach was correct I believe, I would just update the parent into this:
export default class Parent extends React.Component {
constructor(props){
super(props);
this.references = {};
}
onFocus = (ref) => {
this.references[ref].focus();
}
render() {
return (
<View style={styles.container}>
<Child
destinationRef={'two'}
onFocus={this.onFocus}
ref={input => this.references['one'] = input}
/>
<Child ref={input => this.references['two'] = input} />
</View>
);
}
}
and your child to:
export default class Child extends React.Component {
render() {
return (
<View>
<TextInput
placeholder='enter text'
onSubmitEditing={() => {
this.props.onFocus(this.props.destinationRef);
}}
/>
</View>
);
}
}

React Native property not passed to child component

I have the following problem.
I am creating a React Native appliation and I want to pass a click handler to a child component. But when I try to call the click handler in the child component I keep getting a _this.props.onItemPress is not a function Exception.
When I try to pass the function with a .bind(this) inside the parent, it says the function is undefined.
Here's my code:
Parent
constructor(props) {
super(props)
this.handleTodoPress = this.handleTodoPress.bind(this)
}
...
handleTodoPress(event) {
console.warn('Press handled')
}
renderItem ({section, item}) {
return <TodoItem onItemPress={this.handleTodoPress} title={item.title} description={item.description} completed={item.completed} />
}
...
render () {
return (
<View style={styles.container}>
<SectionList
renderSectionHeader={this.renderSectionHeader}
sections={this.state.data}
contentContainerStyle={styles.listContent}
data={this.state.dataObjects}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
initialNumToRender={this.oneScreensWorth}
ListHeaderComponent={this.renderHeader}
SectionSeparatorComponent={this.renderSectionSeparator}
ListEmptyComponent={this.renderEmpty}
ItemSeparatorComponent={this.renderSeparator}
renderSectionFooter={this.renderSectionFooter}
/>
</View>
)
}
}
Child
import React, { Component } from 'react';
import { TouchableOpacity, View, Text, } from 'react-native';
import styles from './Styles/TodoItemStyles'
export default class TodoItem extends Component {
constructor(props) {
super(props)
this.state = {completed: 'Todo'}
this.setCompletedState = this.setCompletedState.bind(this)
}
itemPressed = (e) => {
console.warn(this.props);
this.props.onItemPress(e)
}
setCompletedState() {
if (this.props.completed == true) {
this.setState({completed: 'Completed'})
}
}
componentWillMount() {
this.setCompletedState()
}
render() {
return (
<TouchableOpacity onPress={this.itemPressed}>
<View style={styles.todoContainer}>
<Text style={styles.itemTitle}>{this.props.title}</Text>
<Text style={styles.itemDescription}>{this.props.description}</Text>
<Text style={[styles.itemLabel, this.props.completed ? styles.itemLabelCompleted : styles.itemLabelNotCompleted]}>{this.state.completed}</Text>
</View>
</TouchableOpacity>
);
}
}
TRY:
export default class TodoItem extends Component {
constructor(props) {
super(props)
this.state = {completed: 'Todo'}
this.setCompletedState = this.setCompletedState.bind(this)
}
itemPressed(e){
console.warn(this.props);
this.props.onItemPress(e)
}
setCompletedState() {
if (this.props.completed == true) {
this.setState({completed: 'Completed'})
}
}
componentWillMount() {
this.setCompletedState()
}
render() {
return (
<TouchableOpacity onPress={this.itemPressed}>
<View style={styles.todoContainer}>
<Text style={styles.itemTitle}>{this.props.title}</Text>
<Text style={styles.itemDescription}>{this.props.description}</Text>
<Text style={[styles.itemLabel, this.props.completed ? styles.itemLabelCompleted : styles.itemLabelNotCompleted]}>{this.state.completed}</Text>
</View>
</TouchableOpacity>
);
}
}
when you use
itemPressed = (e) => {
console.warn(this.props);
this.props.onItemPress(e)
}
that notations binds the current context inside the function
I think your problem is that how you are using arrow function for itemPressed. Try rewriting it and binding this for itemPressed the same as you did for setCompletedState.

Categories