react-native-tab-view jump to specific tab from react navigation screen - javascript

I have 2 libs for my navigation. React navigation v5 and react-native-tab-view. 3 tabs from react navigation : Home/Discover/Profile. Discover is a screen with react native tab view. I have few buttons in Home, after press them they should navigate me to Discover tab and specific tab in Tab View. For now, I made the navigation from Home to Discover with react navigation. But how can i jump to a specific tab after i navigate to Discover?
This is sone element in Home which holds the button that will navigate me from Home to Discover:
render() {
const { error, pending, refresh, videos } = this.props;
return (
<HomeViewItem
headerText={'Top Videos'}
footerText={'More Videos'}
navigate={() =>
this.props.navigation.navigate('TabNavigator', {
screen: 'Discover',
}) // this will navigate me to Discover
}
view={this._renderVideos(videos, pending, error, refresh)}
/>
);
}
this is tab view in Discover screen:
export default class DiscoverTabView extends React.Component<DiscoverProps> {
_StreamsRoute = () => <StreamsTabScreen navigation={this.props.navigation} />;
_NewsRoute = () => <NewsTabScreen navigation={this.props.navigation} />;
_VideosRoute = () => <VideosTabScreen navigation={this.props.navigation} />;
_RedditRoute = () => <RedditTabScreen navigation={this.props.navigation} />;
_PicturesRoute = () => (
<PicturesTabScreen navigation={this.props.navigation} />
);
state = {
index: 0,
routes: [
{ key: 'streams', title: 'Streams' },
{ key: 'news', title: 'News' },
{ key: 'videos', title: 'Videos' },
{ key: 'reddit', title: 'Reddit' },
{ key: 'pictures', title: 'Pictures' },
],
};
_handleIndexChange = (index: number) => this.setState({ index });
componentWillUpdate() {}
render() {
const renderTabBar = (
props: SceneRendererProps & { navigationState: State }
) => (
<TabBar
{...props}
indicatorStyle={{ bottom: 6 }}
style={{ backgroundColor: '#0C2B33', elevation: 0, shadowOpacity: 0 }}
scrollEnabled={true}
renderLabel={renderLabel}
renderIndicator={renderIndicator}
tabStyle={{ width: 87, height: 44 }}
/>
);
const renderLabel = ({
route,
focused,
color,
}: {
route: Route;
focused: boolean;
color: String;
}) => {
return (
<View style={{ width: 87, height: 44 }}>
<Text style={focused ? styles.active : styles.inactive}>
{route.title}
</Text>
<Image
source={
route.key === this.state.routes[this.state.routes.length - 1].key
? null
: images.tabViewSeparator
}
style={{ position: 'absolute', alignSelf: 'flex-end', top: 10 }}
/>
<Image
source={
focused ? images.tabViewIconActive : images.tabViewIconInactive
}
style={{
width: 20,
height: 20,
alignSelf: 'center',
position: 'absolute',
top: 21,
}}
/>
</View>
);
};
return (
<TabView
lazy={false}
navigationState={this.state}
renderScene={SceneMap({
streams: this._StreamsRoute,
news: this._NewsRoute,
videos: this._VideosRoute,
reddit: this._RedditRoute,
pictures: this._PicturesRoute,
})}
renderTabBar={renderTabBar}
onIndexChange={this._handleIndexChange}
initialLayout={{ width: Dimensions.get('window').width }}
/>
);
}
}

You do it by using a specific tab action: jumpTo.
The function goes as follows:
import { TabActions } from '#react-navigation/native';
const jumpToAction = TabActions.jumpTo("TabName", { params });
navigation.dispatch(jumpToAction);

Related

TypeError: undefined is not an object (evaluating '_this.state.data)

The error occurs when I try to close the modal window. on the "Close" button. The error says that _this.state.data [imageKey] .urls' is not an object, but I pass the string.
I am receiving JSON from a custom API endpoint. I was able to iterate over the JSON and output some data, but the problem is with the string reference to the image. I am getting the error:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableWithoutFeedback,
Dimensions,
Modal,
ScrollView,
} from 'react-native';
import ImageElement from './component/ImageElement';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
modalVisible: false,
data: [],
};
}
componentDidMount() {
fetch('https://api.unsplash.com/photos/?client_id=cf49c08b444ff4cb9e4d126b7e9f7513ba1ee58de7906e4360afc1a33d1bf4c0')
.then((response) => response.json())
.then((data) => {
this.setState({
data: data,
});
});
}
// getImage() {
// return this.state.modalImage
// }
setModalVisible = (visible, imageKey) => {
this.setState({ modalImage: this.state.data[imageKey].urls.raw });
this.setState({ modalVisible: visible });
};
render() {
let images = this.state.data.map((val, key) => {
return (
<TouchableWithoutFeedback
key={key}
onPress={() => {
this.setModalVisible(true, key);
}}
>
<View style={styles.imagewrap}>
<ImageElement
author={{ url: val.user.profile_image.small }} // фото автора
imgsource={{ url: val.urls.small }} // работа автора
authorNameProp={val.user.name} // имя автора
></ImageElement>
</View>
</TouchableWithoutFeedback>
);
});
return (
<ScrollView>
<View style={styles.container}>
<Modal
style={styles.modal}
animationType={'fade'}
transparent={true}
visible={this.state.modalVisible}
onRequestClose={() => {}}
>
<View style={styles.modal}>
<Text
style={styles.text}
onPress={() => {
this.setModalVisible(false);
}}
>
Close
</Text>
<ImageElement imgsource={{ url: this.state.modalImage }}></ImageElement>
</View>
</Modal>
{images}
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
backgroundColor: 'grey',
overflow: 'scroll',
},
imagewrap: {
margin: 5,
padding: 2,
height: Dimensions.get('window').height / 2 - 60,
width: Dimensions.get('window').width / 2 - 10,
},
modal: {
flex: 1,
padding: 10,
backgroundColor: 'rgba(0,0,0, 0.9)',
},
text: {
color: '#fff',
zIndex: 20,
position: 'absolute',
top: 50,
right: 30,
fontSize: 20,
},
user: {
color: '#fff',
zIndex: 20,
position: 'absolute',
top: 20,
left: 10,
},
});
AppRegistry.registerComponent('ImageGallery', () => ImageGallery);
Issue
Seems you missed passing an index in your close handler this.setModalVisible(false), imageKey is undefined, and thus this.state.data[undefined] is undefined and throws error when you access deeper into the nested properties.
Solution
Conditionally access the data value based on the visible value. Clear out the modalImage state when closing the modal.
setModalVisible = (visible, imageKey) => {
this.setState({
modalImage: visible ? this.state.data[imageKey].urls.raw : null,
modalVisible: visible,
});
}
Alternatively you can just use Optional Chaining to do null checks for you.
setModalVisible = (visible, imageKey) => {
this.setState({
modalImage: this.state.data[imageKey]?.urls?.raw,
modalVisible: visible,
});
}

Add WebView via onClick in Expo React-Native

I need a function that creates new screens with a webview in it.
The main screen of my expo app contains a button "add new Page" which links to a page with a form to add domain, Username, Password.
if this is done, I want a list of pages in my main screen with all pages. for example if I click on "myWebsite1" with the generated link http://user:password#myWebsite1.com this page should be shown in a webview. same for website2, 3 and so on.
Anyone an idea how to do this?
EDIT: I add some code I have right now. For each Task I create, the Domain, User and Password for the webview file should change and be saved at this specific task. (and also open onclick). I turn in a circle
this is my app.js which expo opens first, it contains a Flatlist:
import React, { Component } from "react";
import { AppRegistry, StyleSheet, Text, View, FlatList, AsyncStorage, Button, TextInput, Keyboard, Platform, TouchableWithoutFeedback } from "react-native";
const isAndroid = Platform.OS == "android";
const viewPadding = 10;
const things = {things}
export default class NodeList extends Component {
state = {
tasks: [ ],
text: ""
};
changeTextHandler = text => {
this.setState({ text: text });
};
addTask = () => {
let notEmpty = this.state.text.trim().length > 0;
if (notEmpty) {
this.setState(
prevState => {
let { tasks, text } = prevState;
return {
tasks: tasks.concat({ key: tasks.length, text: text }),
text: ""
};
},
() => Tasks.save(this.state.tasks)
);
}
};
deleteTask = i => {
this.setState(
prevState => {
let tasks = prevState.tasks.slice();
tasks.splice(i, 1);
return { tasks: tasks };
},
() => Tasks.save(this.state.tasks)
);
};
componentDidMount() {
Keyboard.addListener(
isAndroid ? "keyboardDidShow" : "keyboardWillShow",
e => this.setState({ viewMargin: e.endCoordinates.height + viewPadding })
);
Keyboard.addListener(
isAndroid ? "keyboardDidHide" : "keyboardWillHide",
() => this.setState({ viewMargin: viewPadding })
);
Tasks.all(tasks => this.setState({ tasks: tasks || [] }));
}
render() {
return (
<View
style={[styles.container, { paddingBottom: this.state.viewMargin }]}
>
<Text style={styles.appTitle}>Nodes</Text>
<FlatList
style={styles.list}
data={this.state.tasks}
renderItem={({ item, index }) =>
<View>
<View style={styles.listItemCont}>
<TouchableWithoutFeedback onPress={() => Linking.openURL('')}>
<Text style={styles.listItem}>
{item.text}
</Text>
</TouchableWithoutFeedback>
<Button color= "#00BC8C" title="✖" onPress={() => this.deleteTask(index)} />
</View>
<View style={styles.hr} />
</View>}
/>
<TextInput
style={styles.textInput}
onChangeText={this.changeTextHandler}
onSubmitEditing={this.addTask}
value={this.state.text}
placeholder="+ add Node"
returnKeyType="done"
returnKeyLabel="done"
/>
</View>
);
}
}
let Tasks = {
convertToArrayOfObject(tasks, callback) {
return callback(
tasks ? tasks.split("||").map((task, i) => ({ key: i, text: task })) : []
);
},
convertToStringWithSeparators(tasks) {
return tasks.map(task => task.text).join("||");
},
all(callback) {
return AsyncStorage.getItem("TASKS", (err, tasks) =>
this.convertToArrayOfObject(tasks, callback)
);
},
save(tasks) {
AsyncStorage.setItem("TASKS", this.convertToStringWithSeparators(tasks));
}
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#252525",
padding: viewPadding,
paddingTop: 24
},
list: {
width: "100%"
},
listItem: {
paddingTop: 4,
paddingBottom: 2,
fontSize: 18,
color:"#ffff"
},
hr: {
height: 1,
backgroundColor: "gray"
},
listItemCont: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingTop: 10,
},
textInput: {
height: 40,
paddingRight: 10,
paddingLeft: 10,
borderColor: "gray",
borderWidth: isAndroid ? 0 : 1,
width: "100%",
color:"#ffff"
},
appTitle: {
alignItems:"center",
justifyContent: "center",
paddingBottom: 45,
marginTop: 50,
fontSize: 25,
color:"#ffff"
}
});
AppRegistry.registerComponent("NodeList", () => NOdeList);
and here is my second screen, which contains the component for the WebView:
import React, { Component, useState } from "react";
import { BackHandler } from 'react-native';
import { WebView } from 'react-native-webview';
var $ = require( "jquery" );
export default class nodeView extends Component {
constructor(props) {
super(props);
this.WEBVIEW_REF = React.createRef();
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = ()=>{
this.WEBVIEW_REF.current.goBack();
return true;
}
onNavigationStateChange(navState) {
this.setState({
canGoBack: navState.canGoBack
});
}
render(){
return (
<WebView
source={{ uri: `https://${user}:${password}#${domain}` }}
ref={this.WEBVIEW_REF}
style={{ marginTop: 20 }}
onNavigationStateChange={this.onNavigationStateChange.bind(this)}
/>
)
}
}
Create WebView. Create State Which Controls WebView. Add Listener To Button

React Native Elements Checkbox Should be checked after clicking

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

How to view multiple capture image horizontally in react native?

I just want to capture image using camera API
Then Store it in array
then view one by one image horizontally in React native
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
PixelRatio
} from 'react-native';
import ImagePicker from 'react-native-image-picker';
let ret;
export default class Location extends Component {
constructor(props){
super(props);
this.state = {
latitude: null,
longitude: null,
address: 'address',
MyAddress: null,
error: null,
};
}
state = {
avatarSource: null,
videoSource: null
};
selectPhotoTapped() {
const options = {
quality: 1.0,
maxWidth: 500,
maxHeight: 500,
storageOptions: {
skipBackup: true
}
};
To get Image, I used this.
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled photo picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
let source = { uri: response.uri };
// You can also display the image using data:
//let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
avatarSource: source
});
}
});
}
Then how to process to view list of image like adpater.
return (
<View style={{ flexGrow: 1, alignItems: 'center', justifyContent: 'center' }}>
To show the image in one view ,i have done this. i want to view multiple image like view pager.Like [] [] [] []
<TouchableOpacity onPress={this.selectPhotoTapped.bind(this)}>
<View style={[styles.avatar, styles.avatarContainer, {marginBottom: 20}]}>
{ this.state.avatarSource === null ? <Text>Select a Photo</Text> :
<Image style={styles.avatar} source={this.state.avatarSource} />
}
</View>
</TouchableOpacity>
</View>
)
}
}
After few hours i have done this
First save image uri in array then show in list..
let dataStorage = [{uri: response.uri}, ...this.state.dataStorage]
this.setState({dataStorage})
<FlatList
horizontal
data={this.state.dataStorage}
renderItem={({ item: rowData }) => {
return (
<View style={[styles.avatar, styles.avatarContainer, {marginBottom: 20}]}>
{ <Image style={styles.avatar} source={{uri:rowData.uri}} /> }
</View>
);
}
}
keyExtractor={(item, index) => index}
/>
Using Expo's ImagePicker this can be achieved.
Below is my code that might help you.
Note: Its performance is slow but it works.
1) state:
constructor(props) {
super(props);
this.state = {
images: []
};
}
2) openCamera function:
openCamera = async () => {
const { status } = await Permissions.askAsync(
Permissions.CAMERA,
Permissions.CAMERA_ROLL
);
this.setState({
hasCameraPermission: status === 'granted',
hasGalleryPermission: status === 'granted'
});
if (this.state.hasCameraPermission && this.state.hasGalleryPermission) {
ImagePicker.launchCameraAsync({
aspect: [1, 1],
quality: 0.2,
base64: true
})
.then(async result => {
if (!result.cancelled) {
await this.setState({
images: this.state.images.concat(result.uri)
});
Alert.alert(
'Add another picture? ',
null,
[
{
text: 'Yes',
onPress: () => this.openCamera()
},
{ text: 'No' }
],
{ cancelable: false }
);
}
console.log(this.state.images);
})
.catch(error => console.log(error));
}
};
3) To display Image:
showImages = () => {
let temp_image = [];
this.state.images.map((item, index) => {
let tempKey = item + '123';
temp_image.push(
<View key={tempKey}>
<View
key={index}
style={{
height: 100,
width: 100,
borderColor: '#dddddd'
}}
>
<Image
key={index}
source={{ uri: item }}
style={{
flex: 1,
flexDirection: 'row',
backgroundColor: 'silver',
padding: 5,
borderRadius: 5,
height: null,
width: null,
margin: 3,
resizeMode: 'cover'
}}
/>
</View>
<View key={index + 1}>
<TouchableOpacity
key={index + 2}
style={{
flex: 1,
justifyContent: 'center',
alignSelf: 'center',
width: '100%'
}}
onPress={() => {
this.removeImage(index);
this.forceUpdate();
}}
>
<Text
key={index + 3}
style={{
alignSelf: 'center',
color: '#CE3C3E',
fontWeight: 'bold'
}}
>
Delete
</Text>
</TouchableOpacity>
</View>
</View>
);
});
console.log('state images: ', this.state.images);
return temp_image;
};
4) To delete image:
removeImage = index => {
Alert.alert('Delete this image?', null, [
{
text: 'Yes',
onPress: () => {
this.state.images.splice(index, 1);
// console.log(this.state.images);
this.forceUpdate();
}
},
{ text: 'No' }
]);
};
5) And in render() function:
<ScrollView horizontal={true} style={{ flex: 1, flexDirection: 'row' }} >
{this.showImages()}
</ScrollView>

ListItem onPress not working as it should

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.

Categories

Resources